mapdash/frontend/index.html
aaverbitskiy 52a1a7cb2d ui: active-filter chips, empty/loading states, focus/animation polish
- Active-filter chips row under the header: one chip per selected city / brand /
  dimension / manager / status plus search and date bounds, each removable; a
  "Сбросить всё" clears everything. Dropdown gains setSelected()/clear().
- Empty states for the timeline and map: icon + title + subtitle + "Сбросить
  фильтры" button (wired to the same reset). (empty toggled to display:flex.)
- Delayed indeterminate loading bar (250ms threshold so fast loads don't flash),
  covering both the data and the map fetches via an in-flight counter.
- Polish: pop-in animation for dropdown/appearance menus, :focus-visible accent
  rings, :active press on buttons, thin themed scrollbars in panels, tabular
  figures on the timeline date axis and tooltips. New components use the Open
  Props --size-* spacing scale.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-10 16:28:51 +00:00

171 lines
7.4 KiB
HTML
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.

<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Адресная программа</title>
<script>
// Theme is set before first paint (no flash). Dark theme is temporarily
// hidden — force light regardless of stored/OS preference. To re-enable,
// restore the localStorage/prefers-color-scheme logic and unhide the toggle.
document.documentElement.setAttribute('data-theme', 'light');
</script>
</head>
<body>
<div id="load-bar" aria-hidden="true"></div>
<header>
<!-- Group 1: brand + counters -->
<div class="hgroup hgroup-brand">
<div class="brand">
<div class="brand-name">Green Media</div>
<div class="brand-sub">Адресная программа</div>
<div id="status"></div>
</div>
</div>
<!-- Group 1b: view mode switch -->
<div class="hgroup hgroup-modes">
<div class="mode-switch">
<button type="button" class="mode-btn active" id="mode-timeline">График</button>
<button type="button" class="mode-btn" id="mode-map">Карта</button>
<button type="button" class="mode-btn" id="mode-split">Карта и график</button>
</div>
<button type="button" class="theme-toggle" id="theme-toggle" title="Переключить тему" aria-label="Переключить тему"></button>
</div>
<!-- Group 2: fields (4-column grid; dates + search on the 2nd row) -->
<div class="hgroup hgroup-fields">
<div class="field">
<label>Город</label>
<div class="dropdown" id="city-dropdown">
<button type="button" class="dropdown-btn" id="city-btn">
<span id="city-btn-text">Все города</span>
<span class="caret"></span>
</button>
<div class="dropdown-panel" id="city-panel"></div>
</div>
</div>
<div class="field">
<label>Бренд</label>
<div class="dropdown" id="brand-dropdown">
<button type="button" class="dropdown-btn" id="brand-btn">
<span id="brand-btn-text">Все бренды</span>
<span class="caret"></span>
</button>
<div class="dropdown-panel" id="brand-panel"></div>
</div>
</div>
<div class="field">
<label>Размер</label>
<div class="dropdown" id="dimension-dropdown">
<button type="button" class="dropdown-btn" id="dimension-btn">
<span id="dimension-btn-text">Все размеры</span>
<span class="caret"></span>
</button>
<div class="dropdown-panel" id="dimension-panel"></div>
</div>
</div>
<div class="field">
<label>Менеджер</label>
<div class="dropdown" id="manager-dropdown">
<button type="button" class="dropdown-btn" id="manager-btn">
<span id="manager-btn-text">Все менеджеры</span>
<span class="caret"></span>
</button>
<div class="dropdown-panel" id="manager-panel"></div>
</div>
</div>
<div class="field">
<label for="date-start">Дата начала (от)</label>
<input type="date" id="date-start" />
</div>
<div class="field">
<label for="date-end">Дата окончания (до)</label>
<input type="date" id="date-end" />
</div>
<div class="field">
<label>Статус</label>
<div class="dropdown" id="status-dropdown">
<button type="button" class="dropdown-btn" id="status-btn">
<span id="status-btn-text">Все статусы</span>
<span class="caret"></span>
</button>
<div class="dropdown-panel" id="status-panel"></div>
</div>
</div>
<div class="field">
<label for="search">Поиск (адрес / код)</label>
<input type="text" id="search" placeholder="например, Азина" />
</div>
</div>
<!-- Group 3: scale + appearance + checkboxes (compact stack) -->
<div class="hgroup hgroup-controls">
<div class="field zoom-field">
<label for="zoom-slider">Масштаб: <span id="zoom-label">12 месяцев</span></label>
<div class="zoom-row">
<input type="range" id="zoom-slider" min="0" max="9" step="1" value="3" />
</div>
</div>
<div class="checks">
<div class="field checkbox-field">
<label for="show-brand"><input type="checkbox" id="show-brand" checked /> Бренд</label>
</div>
<div class="field checkbox-field">
<label for="show-collisions"><input type="checkbox" id="show-collisions" checked /> Коллизии размещения</label>
</div>
<div class="field checkbox-field">
<label for="show-company"><input type="checkbox" id="show-company" /> Компания</label>
</div>
</div>
</div>
<!-- Appearance ("+") button, pinned to the header's bottom-right corner -->
<div class="decor-wrap">
<button type="button" class="decor-btn" id="decor-btn" aria-label="Оформление" data-tip="Оформление">+</button>
<div class="decor-menu" id="decor-menu"></div>
</div>
</header>
<div id="filter-chips" class="chips" style="display:none"></div>
<div id="view" class="mode-timeline">
<div id="pane-timeline">
<div id="chart-wrap">
<div id="timeline"></div>
<div id="col-resizer" title="Потяните, чтобы изменить ширину колонки"></div>
<div id="empty" class="empty-state" style="display:none">
<svg class="empty-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="8" y1="11" x2="14" y2="11"/></svg>
<div class="empty-title">Ничего не найдено</div>
<div class="empty-sub">Под текущие фильтры нет броней</div>
<button type="button" class="empty-reset" id="empty-reset-timeline">Сбросить фильтры</button>
</div>
</div>
</div>
<div id="split-resizer" title="Потяните, чтобы изменить пропорции"></div>
<div id="pane-map">
<div id="map"></div>
<div id="map-legend">
<span class="lg-item"><span class="lg-dot lg-free"></span><span id="lg-free">свободна</span></span>
<span class="lg-item"><span class="lg-dot lg-busy"></span><span id="lg-busy">занята</span></span>
<span class="lg-item" id="map-counter"></span>
<button type="button" class="lg-nocoords" id="map-nocoords-btn" style="display:none"></button>
</div>
<div id="map-nocoords-panel" style="display:none"></div>
<div id="map-empty" class="empty-state" style="display:none">
<svg class="empty-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 21s-7-6.3-7-11a7 7 0 0 1 14 0c0 4.7-7 11-7 11z"/><circle cx="12" cy="10" r="2.5"/></svg>
<div class="empty-title">Нет поверхностей на карте</div>
<div class="empty-sub">У выбранных поверхностей нет координат</div>
<button type="button" class="empty-reset" id="empty-reset-map">Сбросить фильтры</button>
</div>
</div>
</div>
<div id="tooltip"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>