universal-dashboard/index.html

430 lines
20 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.0" />
<meta
name="description"
content="Навигационная панель экосистемы с разделами, подразделами, поиском и быстрыми переходами."
/>
<title>Панель экосистемы</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<!-- Декоративные фоновые пятна. Они не участвуют в логике и нужны только для глубины фона. -->
<div class="ambient ambient-one"></div>
<div class="ambient ambient-two"></div>
<main class="shell">
<!--
Основная сетка приложения:
слева sticky-меню с деревом навигации, справа каталог карточек.
Ширина левой колонки управляется CSS-переменной --sidebar-width и ресайзером.
-->
<div class="app-layout">
<!-- Боковая панель: поиск, настройки и дерево навигации по всей структуре. -->
<aside class="side-panel" aria-label="Навигация по экосистеме">
<div class="hero-content">
<!-- Шестеренка открывает fixed popup с настройками внешнего вида и поведения. -->
<button
class="settings-button"
type="button"
aria-label="Открыть настройки внешнего вида"
aria-expanded="false"
data-settings-toggle
>
⚙
</button>
<p class="eyebrow" id="page-title">Панель экосистемы</p>
<!-- Поиск фильтрует каталог и подсвечивает совпадения в дереве и карточках. -->
<label class="search-field" data-search-field>
<input
type="search"
placeholder="Grafana, S3, журнал, сервер..."
autocomplete="off"
data-search-input
/>
</label>
<!-- Дерево генерируется из ecosystemSections в script.js. -->
<nav class="nav-tree" aria-label="Дерево навигации" data-nav-tree></nav>
</div>
<!-- Горизонтальная ручка высоты верхней панели (режим «Сверху»). -->
<div
class="top-bar-resizer"
role="separator"
aria-orientation="horizontal"
aria-label="Изменить высоту верхней панели"
data-top-bar-resizer
hidden
></div>
</aside>
<!-- Вертикальная ручка для изменения ширины бокового меню мышью/указателем. -->
<div
class="sidebar-resizer"
role="separator"
aria-orientation="vertical"
aria-label="Изменить ширину бокового меню"
data-sidebar-resizer
></div>
<!-- Затемнение страницы за popup-настройками. -->
<div class="settings-overlay" data-settings-overlay></div>
<!--
Popup настроек:
- тема;
- режим отображения карточек;
- видимость нумерации;
- видимость тегов в дереве;
- авто-раскрытие дерева при поиске;
- цветовой акцент.
-->
<div class="control-panel" aria-label="Настройки панели" data-settings-panel>
<div class="settings-panel-head">
<p class="eyebrow settings-panel-eyebrow">Настройки</p>
<button class="settings-close" type="button" aria-label="Закрыть настройки" data-settings-close>
×
</button>
</div>
<!-- Переключение светлой/темной темы. Значение сохраняется в localStorage. -->
<section class="settings-section" data-settings-section="layout">
<p class="settings-section-title">Макет</p>
<div class="control-group">
<span>Панель навигации</span>
<button class="segmented is-active" type="button" data-nav-layout="sidebar">
Сбоку
</button>
<button class="segmented" type="button" data-nav-layout="top">
Сверху
</button>
</div>
<p class="settings-section-hint">
«Сверху» — компактная шапка. Дерево включается отдельно переключателем ниже.
</p>
<label class="toggle-row" data-feature="allowShowTreeChange">
<span>
<strong>Показывать дерево</strong>
<small>В режимах «Сбоку» и «Сверху»</small>
</span>
<input type="checkbox" data-show-tree checked />
</label>
<label class="toggle-row" data-feature="allowSidebarResize">
<span>
<strong>Ручки изменения размера</strong>
<small>Ширина меню или высота шапки</small>
</span>
<input type="checkbox" data-show-resize-handles checked />
</label>
</section>
<details class="settings-section settings-section-collapsible" data-settings-section="dimensions">
<summary class="settings-section-summary">
<span class="settings-section-title">Габариты</span>
<span class="collapse-indicator" aria-hidden="true">⌄</span>
</summary>
<div class="settings-section-body">
<p class="settings-section-hint">
Ограничения ширины страницы, бокового меню и верхней шапки. Значения применяются сразу;
текущий размер меню и шапки можно также менять перетаскиванием ручек на странице.
Допустимые диапазоны ползунков задаёт администратор в <code>settings.json</code> →
<code>limits</code>.
</p>
<label
class="accent-custom-row layout-limit-row"
data-tooltip="Максимальная ширина всей панели (.shell): насколько широко вместе могут располагаться меню и каталог."
>
<span>Ширина контента (max)</span>
<input type="range" data-layout-limit="shellMaxWidth" />
<output data-layout-limit-value="shellMaxWidth">2800</output>
</label>
<label
class="accent-custom-row layout-limit-row"
data-tooltip="Минимальная ширина бокового меню при перетаскивании вертикальной ручки между меню и каталогом."
>
<span>Меню: мин. ширина</span>
<input type="range" data-layout-limit="sidebarMinWidth" />
<output data-layout-limit-value="sidebarMinWidth">260</output>
</label>
<label
class="accent-custom-row layout-limit-row"
data-tooltip="Максимальная ширина меню, когда элементы дерева в папках показываются в одну колонку."
>
<span>Меню: макс. (1 кол.)</span>
<input type="range" data-layout-limit="sidebarMaxWidth" />
<output data-layout-limit-value="sidebarMaxWidth">800</output>
</label>
<label
class="accent-custom-row layout-limit-row"
data-tooltip="Верхний предел ширины меню при нескольких колонках в дереве. Фактический максимум также зависит от базы и шага колонки."
>
<span>Меню: макс. (неск. кол.)</span>
<input type="range" data-layout-limit="sidebarMaxWidthWide" />
<output data-layout-limit-value="sidebarMaxWidthWide">1400</output>
</label>
<label
class="accent-custom-row layout-limit-row"
data-tooltip="База формулы ширины меню при нескольких колонках: min(макс. неск. кол., база + колонки × шаг)."
>
<span>Дерево: база ширины</span>
<input type="range" data-layout-limit="treeSidebarBaseWidth" />
<output data-layout-limit-value="treeSidebarBaseWidth">420</output>
</label>
<label
class="accent-custom-row layout-limit-row"
data-tooltip="Сколько пикселей добавляется к базовой ширине меню за каждую колонку элементов в папках дерева."
>
<span>Дерево: ширина колонки</span>
<input type="range" data-layout-limit="treeSidebarColumnWidth" />
<output data-layout-limit-value="treeSidebarColumnWidth">120</output>
</label>
<label
class="accent-custom-row layout-limit-row"
data-tooltip="Минимальная высота верхней шапки в режиме «Сверху» — нижняя граница при перетаскивании горизонтальной ручки."
>
<span>Шапка: мин. высота</span>
<input type="range" data-layout-limit="topBarMinHeight" />
<output data-layout-limit-value="topBarMinHeight">80</output>
</label>
<label
class="accent-custom-row layout-limit-row"
data-tooltip="Максимальная высота верхней шапки в режиме «Сверху». Также ограничена примерно 75% высоты окна браузера."
>
<span>Шапка: макс. высота</span>
<input type="range" data-layout-limit="topBarMaxHeight" />
<output data-layout-limit-value="topBarMaxHeight">560</output>
</label>
</div>
</details>
<section class="settings-section" data-settings-section="catalog">
<p class="settings-section-title">Каталог</p>
<!-- Режимы каталога: обычные/компактные плитки и списки. -->
<div class="control-group view-group" data-feature="allowViewChange">
<span>Вид</span>
<button class="segmented is-active" type="button" data-view="cards">
Плитки
</button>
<button class="segmented" type="button" data-view="list">
Список
</button>
<button class="segmented" type="button" data-view="compact-cards">
Компакт плитки
</button>
<button class="segmented" type="button" data-view="compact-list">
Компакт список
</button>
</div>
<div class="catalog-columns-group" data-feature="allowCatalogColumnsChange">
<p class="settings-section-hint">Колонок в строке для каждого вида каталога.</p>
<label class="accent-custom-row">
<span>Плитки</span>
<input type="range" data-catalog-columns="catalogCardsColumns" />
<output data-catalog-columns-value="catalogCardsColumns">3</output>
</label>
<label class="accent-custom-row">
<span>Список</span>
<input type="range" data-catalog-columns="catalogListColumns" />
<output data-catalog-columns-value="catalogListColumns">1</output>
</label>
<label class="accent-custom-row">
<span>Компакт плитки</span>
<input type="range" data-catalog-columns="catalogCompactCardsColumns" />
<output data-catalog-columns-value="catalogCompactCardsColumns">5</output>
</label>
<label class="accent-custom-row">
<span>Компакт список</span>
<input type="range" data-catalog-columns="catalogCompactListColumns" />
<output data-catalog-columns-value="catalogCompactListColumns">3</output>
</label>
</div>
<!-- Показывать номера разделов, подразделов и элементов. -->
<label class="toggle-row" data-feature="allowShowNumbers">
<span>
<strong>Показывать нумерацию</strong>
<small>Разделы, подразделы и элементы</small>
</span>
<input type="checkbox" data-show-numbers />
</label>
</section>
<section class="settings-section" data-settings-section="tree">
<p class="settings-section-title">Дерево</p>
<label class="accent-custom-row">
<span>Колонок</span>
<input type="range" min="1" max="6" step="1" value="2" data-tree-columns />
<output data-tree-columns-value>2</output>
</label>
<label class="toggle-row">
<span>
<strong>Показывать теги</strong>
<small>Оформление как на карточках</small>
</span>
<input type="checkbox" data-show-tree-tags />
</label>
<label class="toggle-row">
<span>
<strong>Показывать тип</strong>
<small>Подпись типа сервиса</small>
</span>
<input type="checkbox" data-show-tree-type />
</label>
<div class="control-group">
<span>Теги и тип</span>
<button class="segmented is-active" type="button" data-tree-meta-layout="inline">
Сбоку
</button>
<button class="segmented" type="button" data-tree-meta-layout="stacked">
Снизу
</button>
</div>
<label class="toggle-row">
<span>
<strong>Авто раскрывать поиск</strong>
<small>Сворачивать ветки без совпадений</small>
</span>
<input type="checkbox" data-auto-collapse-search />
</label>
</section>
<section class="settings-section" data-settings-section="appearance">
<p class="settings-section-title">Оформление</p>
<div class="control-group" data-feature="allowThemeChange">
<span>Тема</span>
<button class="segmented is-active" type="button" data-theme="dark">
Темная
</button>
<button class="segmented" type="button" data-theme="light">
Светлая
</button>
</div>
<!-- Выбор акцентного цвета интерфейса. -->
<div class="control-group accent-group" data-feature="allowAccentChange">
<span>Акцент</span>
<button
class="accent-swatch is-active"
type="button"
data-accent="violet"
aria-label="Фиолетовый акцент"
></button>
<button
class="accent-swatch"
type="button"
data-accent="cyan"
aria-label="Голубой акцент"
></button>
<button
class="accent-swatch"
type="button"
data-accent="lime"
aria-label="Лаймовый акцент"
></button>
<button
class="accent-swatch"
type="button"
data-accent="amber"
aria-label="Янтарный акцент"
></button>
<button
class="accent-swatch accent-swatch-custom"
type="button"
data-accent="custom"
aria-label="Свой градиент"
title="Свой градиент"
>
<span class="accent-swatch-label">Свой</span>
</button>
</div>
<!-- Настройки пользовательского linear-gradient акцента. -->
<div class="accent-custom-panel" data-accent-custom-panel data-feature="allowAccentChange" hidden>
<p class="accent-custom-title">Свой градиент</p>
<label class="accent-custom-row">
<span>Угол</span>
<input
type="range"
min="0"
max="360"
step="1"
value="135"
data-custom-accent-angle
/>
<output data-custom-accent-angle-value>135°</output>
</label>
<label class="accent-custom-row">
<span>Цвет от</span>
<input type="color" value="#8b5cf6" data-custom-accent-from />
</label>
<label class="accent-custom-row">
<span>Цвет до</span>
<input type="color" value="#22d3ee" data-custom-accent-to />
</label>
<div class="accent-custom-preview" data-custom-accent-preview aria-hidden="true"></div>
</div>
</section>
</div>
<!-- Каталог карточек генерируется из ecosystemSections в script.js. -->
<section class="catalog cards-view" aria-live="polite" data-catalog-root></section>
<!-- Шаблон ошибки загрузки settings.json / panel data. -->
<template id="config-error-template">
<div class="empty-state config-error-state">
<img src="assets/config.svg" alt="" />
<h2>Не удалось загрузить панель</h2>
<p data-config-error-message></p>
</div>
</template>
<!-- Шаблон состояния, когда поиск не нашел ни одного элемента. -->
<template id="empty-template">
<div class="empty-state">
<img src="assets/search.svg" alt="" />
<h2>Ничего не найдено</h2>
<p>Попробуй изменить запрос или искать по названию системы, тегу или роли.</p>
</div>
</template>
</div>
</main>
<script src="script.js" data-ecosystem-panel defer></script>
</body>
</html>