| assets | ||
| index.html | ||
| panel-data.json | ||
| README.md | ||
| script.js | ||
| settings.json | ||
| styles.css | ||
Панель экосистемы
Статическая навигационная панель для быстрого доступа к сервисам инфраструктуры. Поддерживает иерархию раздел → подраздел → элемент, поиск, дерево навигации, несколько режимов отображения и настройку внешнего вида.
Стек: HTML, CSS, vanilla JavaScript. Без сборщиков и фреймворков.
Возможности
- Древовидная навигация слева в стиле файлового менеджера
- Каталог карточек справа с collapsible-разделами
- Поиск по названию, тегам, типу сервиса и родительским разделам
- 4 режима отображения: плитки, список, компактные плитки, компактный список
- Темы: светлая / тёмная, 4 пресета акцента + свой градиент
- Настройки через popup (иконка ⚙)
- Изменяемая ширина бокового меню (drag)
- Сохранение состояния в
localStorage(настройки UI, раскрытие веток) - Конфигурация через JSON — локальный объект или загрузка по URL
Быстрый старт
Панель использует fetch, поэтому её нужно открывать через HTTP-сервер, а не напрямую как file://.
cd ecosystem
npx serve .
Открой в браузере адрес, который покажет сервер (обычно http://localhost:3000).
Структура проекта
ecosystem/
├── index.html # Разметка страницы
├── styles.css # Стили, темы, адаптив
├── script.js # Логика, рендер, настройки
├── settings.json # Источник данных панели (URL или inline)
├── panel-data.json # Данные навигации (по умолчанию)
├── assets/ # SVG-иконки сервисов
└── README.md
Конфигурация
settings.json
Указывает, откуда загружать данные панели.
Вариант 1 — загрузка из файла или URL:
{
"dataUrl": "./panel-data.json"
}
Можно указать внешний адрес:
{
"dataUrl": "https://example.com/ecosystem/panel-data.json"
}
Вариант 2 — inline-объект в том же файле:
{
"dataUrl": "",
"data": {
"title": "Панель экосистемы",
"sections": []
}
}
Если
dataUrlне пустой, он имеет приоритет над полемdata.
При ошибке загрузки или невалидном JSON на странице показывается экран с описанием проблемы.
panel-data.json
Основной файл с содержимым панели.
{
"title": "Панель экосистемы",
"sections": [
{
"id": "user",
"number": "1",
"title": "Интерфейс пользователя",
"description": "Описание раздела",
"groups": [
{
"id": "message-filtering",
"number": "1.1",
"title": "Управление фильтрацией",
"description": "Описание подраздела",
"items": [
{
"number": "1.1.1",
"title": "Редактирование правил",
"type": "rules",
"tags": ["правила", "фильтрация"],
"url": "https://rules.example.com"
}
]
}
]
}
],
"serviceMeta": {}
}
Поля данных
| Уровень | Поля | Описание |
|---|---|---|
| Корень | title |
Заголовок панели (sidebar + <title>) |
sections |
Массив разделов | |
serviceMeta |
Опционально: доп. типы сервисов | |
| section | id, number, title, description, groups |
Крупный раздел |
| group | id, number, title, description, items |
Подраздел |
| item | number, title, type, tags, url |
Кликабельный элемент |
type— ключ изserviceMeta(определяет иконку и подпись типа)tags— используются в поиске и опционально в деревеurl— ссылка перехода;"#"означает заглушку (клик не ведёт никуда)
Типы сервисов (serviceMeta)
Базовые типы заданы в script.js:
ceph, cloudbeaver, config, gitea, grafana, ipmi, kubernetes, ldap, messages, opensearch, postgresql, prometheus, rabbitmq, redmine, rules, xpath, xmpp
В panel-data.json можно добавить или переопределить типы:
{
"serviceMeta": {
"my-service": {
"label": "My Service",
"icon": "assets/config.svg"
}
}
}
Настройки интерфейса (⚙)
Доступны в popup-окне и сохраняются в localStorage (ecosystem-panel-preferences):
| Настройка | Описание |
|---|---|
| Тема | Светлая / тёмная |
| Вид | Плитки, список, компакт плитки, компакт список |
| Нумерация | Показывать номера разделов, подразделов и элементов |
| Теги дерева | Поисковые теги рядом с элементами в дереве |
| 2 колонки в дереве | Элементы папок в 2 колонки (взаимоисключимо с тегами) |
| Авто раскрывать поиск | При поиске сворачивать ветки без совпадений |
| Акцент | violet, cyan, lime, amber или свой градиент |
Свой градиент
Кнопка «Свой» открывает настройки:
- угол (0–360°)
- цвет «от» и «до»
Значения сохраняются в localStorage.
Поведение интерфейса
Поиск
Фильтрует каталог и подсвечивает совпадения в дереве и карточках. Ищет по:
- названию элемента
- номеру
- тегам
- типу сервиса
- названиям родительских разделов
Дерево навигации
- Клик по папке — раскрытие/сворачивание
- Клик по названию — прокрутка к элементу в каталоге
- Состояние раскрытия сохраняется отдельно для дерева и контента (
ecosystem-panel-collapse-state)
Адаптив
- Touch-устройства (
pointer: coarse/hover: none): stacked-layout, меню сверху - Мышь (
pointer: fine+hover: hover): sidebar + resizer + каталог в колонках - 2 колонки в дереве на touch: в portrait или при ширине от 520px
Ширина layout
- Обычный режим: max 1560px, sidebar до 560px
- Режим «2 колонки в дереве»: max 1920px, sidebar до 760px
localStorage
| Ключ | Содержимое |
|---|---|
ecosystem-panel-preferences |
Тема, акцент, вид, ширина sidebar, toggle-настройки |
ecosystem-panel-collapse-state |
Раскрытые/свернутые ветки дерева и каталога |
Разработка
Добавить новый элемент
- Открой
panel-data.json - Найди нужный
groupвsections - Добавь объект в
items:
{
"number": "2.5.3",
"title": "Новый сервис",
"type": "gitea",
"tags": ["gitea", "новый"],
"url": "https://gitea.example.com"
}
- Обнови страницу
Добавить новую иконку
- Положи SVG в
assets/ - Зарегистрируй тип в
serviceMetaвнутриpanel-data.jsonили используй существующийtype
Внешний источник данных
Укажи URL в settings.json:
{
"dataUrl": "https://your-server/panel-data.json"
}
Убедись, что сервер отдаёт корректный Content-Type: application/json и разрешает CORS, если домен отличается от панели.
Ограничения
- Требуется HTTP-сервер (
fetchне работает сfile://) - Внешний
dataUrlдолжен быть доступен по CORS - Настройки UI хранятся локально в браузере и не синхронизируются между устройствами
Лицензия
Приватный проект. Используй и изменяй по своему усмотрению.