429 lines
20 KiB
HTML
429 lines
20 KiB
HTML
<!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="../shared/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" data-show-when-sidebar>
|
||
<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="../shared/assets/config.svg" alt="" />
|
||
<h2>Не удалось загрузить панель</h2>
|
||
<p data-config-error-message></p>
|
||
</div>
|
||
</template>
|
||
|
||
<!-- Шаблон состояния, когда поиск не нашел ни одного элемента. -->
|
||
<template id="empty-template">
|
||
<div class="empty-state">
|
||
<img src="../shared/assets/search.svg" alt="" />
|
||
<h2>Ничего не найдено</h2>
|
||
<p>Попробуй изменить запрос или искать по названию системы, тегу или роли.</p>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</main>
|
||
|
||
<script src="../shared/script.js" data-ecosystem-panel data-asset-base="../shared/" defer></script>
|
||
</body>
|
||
</html>
|