добавлена возможность настраивать каждый элемент (узоры)
This commit is contained in:
parent
50a04e3856
commit
26dc3bac2b
74
README.md
74
README.md
@ -33,6 +33,7 @@
|
|||||||
- **Поиск** по названию, тегам, типу сервиса и родительским разделам
|
- **Поиск** по названию, тегам, типу сервиса и родительским разделам
|
||||||
- **4 режима отображения**: плитки, список, компактные плитки, компактный список
|
- **4 режима отображения**: плитки, список, компактные плитки, компактный список
|
||||||
- **Темы**: светлая / тёмная, 4 пресета акцента + свой градиент
|
- **Темы**: светлая / тёмная, 4 пресета акцента + свой градиент
|
||||||
|
- **Узоры панелей** — соты, точки, сетка и др.; отдельные варианты для светлой темы; можно отключить
|
||||||
- **Настройки** через popup (иконка ⚙)
|
- **Настройки** через popup (иконка ⚙)
|
||||||
- **Изменяемая ширина** бокового меню и **высота** верхней шапки (drag, можно скрыть ручки)
|
- **Изменяемая ширина** бокового меню и **высота** верхней шапки (drag, можно скрыть ручки)
|
||||||
- **Габариты** — лимиты ширины контента, меню и шапки (⚙, для администратора)
|
- **Габариты** — лимиты ширины контента, меню и шапки (⚙, для администратора)
|
||||||
@ -126,6 +127,29 @@ ecosystem/
|
|||||||
"theme": "dark",
|
"theme": "dark",
|
||||||
"view": "cards",
|
"view": "cards",
|
||||||
"accent": "violet",
|
"accent": "violet",
|
||||||
|
"customAccentFrom": "#8b5cf6",
|
||||||
|
"customAccentTo": "#22d3ee",
|
||||||
|
"customAccentAngle": 135,
|
||||||
|
"panelPatternNav": "hex",
|
||||||
|
"panelPatternNavOpacity": 70,
|
||||||
|
"panelPatternNavHeight": 45,
|
||||||
|
"panelPatternNavGradientOpacity": 80,
|
||||||
|
"panelPatternNavGradientHeight": 40,
|
||||||
|
"panelPatternSection": "hex",
|
||||||
|
"panelPatternSectionOpacity": 70,
|
||||||
|
"panelPatternSectionHeight": 45,
|
||||||
|
"panelPatternSectionGradientOpacity": 80,
|
||||||
|
"panelPatternSectionGradientHeight": 40,
|
||||||
|
"panelPatternGroup": "none",
|
||||||
|
"panelPatternGroupOpacity": 70,
|
||||||
|
"panelPatternGroupHeight": 45,
|
||||||
|
"panelPatternGroupGradientOpacity": 80,
|
||||||
|
"panelPatternGroupGradientHeight": 40,
|
||||||
|
"panelPatternItem": "none",
|
||||||
|
"panelPatternItemOpacity": 70,
|
||||||
|
"panelPatternItemHeight": 45,
|
||||||
|
"panelPatternItemGradientOpacity": 80,
|
||||||
|
"panelPatternItemGradientHeight": 40,
|
||||||
"showNumbers": false,
|
"showNumbers": false,
|
||||||
"showTreeTags": true,
|
"showTreeTags": true,
|
||||||
"showTreeType": false,
|
"showTreeType": false,
|
||||||
@ -146,7 +170,8 @@ ecosystem/
|
|||||||
"catalogListColumns": 1,
|
"catalogListColumns": 1,
|
||||||
"catalogCompactCardsColumns": 5,
|
"catalogCompactCardsColumns": 5,
|
||||||
"catalogCompactListColumns": 3,
|
"catalogCompactListColumns": 3,
|
||||||
"searchPlaceholder": "Grafana, S3, журнал, сервер..."
|
"searchPlaceholder": "Grafana, S3, журнал, сервер...",
|
||||||
|
"settingsPanelWidth": 460
|
||||||
},
|
},
|
||||||
"limits": {
|
"limits": {
|
||||||
"shellMaxWidth": { "min": 1200, "max": 3840 },
|
"shellMaxWidth": { "min": 1200, "max": 3840 },
|
||||||
@ -173,7 +198,8 @@ ecosystem/
|
|||||||
"allowSidebarResize": true,
|
"allowSidebarResize": true,
|
||||||
"allowLayoutLimitsChange": true,
|
"allowLayoutLimitsChange": true,
|
||||||
"allowThemeChange": true,
|
"allowThemeChange": true,
|
||||||
"allowAccentChange": true
|
"allowAccentChange": true,
|
||||||
|
"allowPanelPatternChange": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -189,6 +215,13 @@ ecosystem/
|
|||||||
| `customAccentFrom` | `#rrggbb` | Цвет «от» для `accent: "custom"` (по умолчанию `#8b5cf6`) |
|
| `customAccentFrom` | `#rrggbb` | Цвет «от» для `accent: "custom"` (по умолчанию `#8b5cf6`) |
|
||||||
| `customAccentTo` | `#rrggbb` | Цвет «до» для `accent: "custom"` (по умолчанию `#22d3ee`) |
|
| `customAccentTo` | `#rrggbb` | Цвет «до» для `accent: "custom"` (по умолчанию `#22d3ee`) |
|
||||||
| `customAccentAngle` | `0`–`360` | Угол градиента в градусах (по умолчанию `135`) |
|
| `customAccentAngle` | `0`–`360` | Угол градиента в градусах (по умолчанию `135`) |
|
||||||
|
| `panelPatternNav` … `panelPatternItem` | см. [узоры панелей](#узоры-панелей) | Тип узора для каждого типа блоков (`none`, `hex`, …) |
|
||||||
|
| `panelPattern{Nav\|Section\|Group\|Item}Opacity` | `0`–`100` | Прозрачность узора в % (по умолчанию `70`) |
|
||||||
|
| `panelPattern{Nav\|Section\|Group\|Item}Height` | `0`–`100` | Высота узора в % (по умолчанию `45`; `0` — скрыть) |
|
||||||
|
| `panelPattern{Nav\|Section\|Group\|Item}Fade` | `0`–`100` | Ширина зоны затухания узора в % высоты блока: `0` — резкий обрыв на линии высоты, `100` — плавное затухание от верха (по умолчанию `10`) |
|
||||||
|
| `panelPattern{Nav\|Section\|Group\|Item}GradientOpacity` | `0`–`100` | Прозрачность акцентного градиента в % (по умолчанию `80`) |
|
||||||
|
| `panelPattern{Nav\|Section\|Group\|Item}GradientHeight` | `0`–`100` | Высота градиента в % (по умолчанию `40`) |
|
||||||
|
| `panelPattern{Nav\|Section\|Group\|Item}GradientFade` | `0`–`100` | Зона затухания градиента (по умолчанию `8`) |
|
||||||
| `showNumbers` | `true`, `false` | Показывать номера разделов, подразделов и элементов |
|
| `showNumbers` | `true`, `false` | Показывать номера разделов, подразделов и элементов |
|
||||||
| `showTreeTags` | `true`, `false` | Теги элементов в дереве (оформление как на карточках) |
|
| `showTreeTags` | `true`, `false` | Теги элементов в дереве (оформление как на карточках) |
|
||||||
| `showTreeType` | `true`, `false` | Подпись типа сервиса в дереве |
|
| `showTreeType` | `true`, `false` | Подпись типа сервиса в дереве |
|
||||||
@ -210,6 +243,7 @@ ecosystem/
|
|||||||
| `catalogCompactCardsColumns` | см. `limits.catalogCompactCardsColumns` | Колонок в строке в режиме «Компакт плитки» |
|
| `catalogCompactCardsColumns` | см. `limits.catalogCompactCardsColumns` | Колонок в строке в режиме «Компакт плитки» |
|
||||||
| `catalogCompactListColumns` | см. `limits.catalogCompactListColumns` | Колонок в строке в режиме «Компакт список» |
|
| `catalogCompactListColumns` | см. `limits.catalogCompactListColumns` | Колонок в строке в режиме «Компакт список» |
|
||||||
| `searchPlaceholder` | произвольная строка | Текст-подсказка в поле поиска |
|
| `searchPlaceholder` | произвольная строка | Текст-подсказка в поле поиска |
|
||||||
|
| `settingsPanelWidth` | `limits.settingsPanelWidth` (по умолчанию `320`–`720`) | Ширина popup настроек в px (по умолчанию `460`) |
|
||||||
|
|
||||||
| `limits` | Формат | Описание |
|
| `limits` | Формат | Описание |
|
||||||
|----------|--------|----------|
|
|----------|--------|----------|
|
||||||
@ -243,6 +277,7 @@ ecosystem/
|
|||||||
| `allowLayoutLimitsChange` | `true`, `false` | Раздел ⚙ «Габариты»: лимиты ширины контента и навигации |
|
| `allowLayoutLimitsChange` | `true`, `false` | Раздел ⚙ «Габариты»: лимиты ширины контента и навигации |
|
||||||
| `allowThemeChange` | `true`, `false` | Светлая / тёмная тема |
|
| `allowThemeChange` | `true`, `false` | Светлая / тёмная тема |
|
||||||
| `allowAccentChange` | `true`, `false` | Пресеты и свой градиент |
|
| `allowAccentChange` | `true`, `false` | Пресеты и свой градиент |
|
||||||
|
| `allowPanelPatternChange` | `true`, `false` | Выбор узора панелей в ⚙ → Оформление |
|
||||||
|
|
||||||
Пользовательские изменения сохраняются в `localStorage`, но заблокированные `features` всегда возвращаются к `defaults`.
|
Пользовательские изменения сохраняются в `localStorage`, но заблокированные `features` всегда возвращаются к `defaults`.
|
||||||
|
|
||||||
@ -404,11 +439,11 @@ Popup сгруппирован по разделам. Доступные бло
|
|||||||
|
|
||||||
| Раздел | Настройки |
|
| Раздел | Настройки |
|
||||||
|--------|-----------|
|
|--------|-----------|
|
||||||
| **Макет** | **Сбоку** / **Сверху**; toggle «Показывать дерево»; toggle «Ручки изменения размера» |
|
| **Макет** | **Сбоку** / **Сверху**; toggle «Показывать дерево»; toggle «Ручки изменения размера»; слайдер «Ширина настроек» |
|
||||||
| **Габариты** | Лимиты ширины контента, меню и шапки (сворачиваемый блок; при `allowLayoutLimitsChange`) |
|
| **Габариты** | Лимиты ширины контента, меню и шапки (сворачиваемый блок; при `allowLayoutLimitsChange`) |
|
||||||
| **Каталог** | Вид карточек, колонок в строке для каждого вида, нумерация |
|
| **Каталог** | Вид карточек, колонок в строке для каждого вида, нумерация |
|
||||||
| **Дерево** | Колонок 1–6, теги, тип, расположение мета, авто-раскрытие (при `showTree: true`) |
|
| **Дерево** | Колонок 1–6, теги, тип, расположение мета, авто-раскрытие (при `showTree: true`) |
|
||||||
| **Оформление** | Тема, акцент, свой градиент |
|
| **Оформление** | Тема, акцент, узор панелей, свой градиент |
|
||||||
|
|
||||||
### Режим «Сверху»
|
### Режим «Сверху»
|
||||||
|
|
||||||
@ -427,6 +462,35 @@ Popup сгруппирован по разделам. Доступные бло
|
|||||||
|
|
||||||
Значения сохраняются в `localStorage`.
|
Значения сохраняются в `localStorage`.
|
||||||
|
|
||||||
|
### Узоры панелей
|
||||||
|
|
||||||
|
Настраиваются в ⚙ → **Оформление** (если `allowPanelPatternChange: true`): четыре схлопывающиеся панели — **Панель навигации**, **Раздел**, **Подраздел**, **Элемент**. В каждой — свой тип узора и слайдеры.
|
||||||
|
|
||||||
|
| Значение `panelPattern*` | Описание |
|
||||||
|
|--------------------------|----------|
|
||||||
|
| `none` | Без узора — только акцентный градиент (если применим) |
|
||||||
|
| `hex` | Соты |
|
||||||
|
| `dots` | Точечная сетка |
|
||||||
|
| `grid` | Линейная сетка |
|
||||||
|
| `diagonal` | Диагональные полосы |
|
||||||
|
| `cross` | Перекрёстная штриховка |
|
||||||
|
| `mesh` | Точки цвета акцента |
|
||||||
|
|
||||||
|
По умолчанию для **навигации** и **разделов** — `hex`; для **подразделов** и **элементов** — `none`.
|
||||||
|
|
||||||
|
| Панель | Preference (префикс) | DOM |
|
||||||
|
|--------|----------------------|-----|
|
||||||
|
| Панель навигации | `panelPatternNav*` | `.hero-content` |
|
||||||
|
| Раздел | `panelPatternSection*` | `.catalog-section` |
|
||||||
|
| Подраздел | `panelPatternGroup*` | `.catalog-group` |
|
||||||
|
| Элемент | `panelPatternItem*` | `.nav-card` — только узор, без акцентного градиента |
|
||||||
|
|
||||||
|
В каждой панели (кроме «Элемент») — шесть слайдеров: прозрачность, высота и **переход** узора; то же для градиента. Для «Элемент» — три слайдера узора (без градиента). **Переход** задаёт ширину зоны затухания: `0%` — резкий обрыв на линии «высоты», большее значение — более плавное исчезновение (при значении ≥ высоты узор растворяется от самого верха блока).
|
||||||
|
|
||||||
|
Старые ключи (`panelPattern`, `panelPatternOnNav`, …) при загрузке автоматически мигрируют в per-target формат, если в `localStorage` ещё нет `panelPatternNav`.
|
||||||
|
|
||||||
|
Значения сохраняются в `localStorage` и выставляют `data-panel-pattern-*` на `<html>` и CSS-переменные `--panel-pattern-{nav|section|group|item}-*`, `--panel-gradient-{target}-*`.
|
||||||
|
|
||||||
## Поведение интерфейса
|
## Поведение интерфейса
|
||||||
|
|
||||||
### Поиск
|
### Поиск
|
||||||
@ -464,7 +528,7 @@ Popup сгруппирован по разделам. Доступные бло
|
|||||||
|
|
||||||
| Ключ | Содержимое |
|
| Ключ | Содержимое |
|
||||||
|------|------------|
|
|------|------------|
|
||||||
| `ecosystem-panel-preferences` | Тема, акцент, вид, ширина sidebar, toggle-настройки |
|
| `ecosystem-panel-preferences` | Тема, акцент, узор, вид, колонки каталога, ширина sidebar, toggle-настройки |
|
||||||
| `ecosystem-panel-collapse-state` | Раскрытые/свернутые ветки дерева и каталога |
|
| `ecosystem-panel-collapse-state` | Раскрытые/свернутые ветки дерева и каталога |
|
||||||
|
|
||||||
## Разработка
|
## Разработка
|
||||||
|
|||||||
@ -126,6 +126,11 @@
|
|||||||
</span>
|
</span>
|
||||||
<input type="checkbox" data-show-resize-handles checked />
|
<input type="checkbox" data-show-resize-handles checked />
|
||||||
</label>
|
</label>
|
||||||
|
<label class="accent-custom-row settings-width-row">
|
||||||
|
<span>Ширина настроек</span>
|
||||||
|
<input type="range" data-settings-panel-width />
|
||||||
|
<output data-settings-panel-width-value>460px</output>
|
||||||
|
</label>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<details class="settings-section settings-section-collapsible" data-settings-section="dimensions">
|
<details class="settings-section settings-section-collapsible" data-settings-section="dimensions">
|
||||||
@ -368,6 +373,114 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="pattern-targets-panel" data-pattern-targets-panel data-feature="allowPanelPatternChange">
|
||||||
|
<p class="settings-section-hint">Узор и градиент настраиваются отдельно для каждого типа блоков.</p>
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="nav">
|
||||||
|
<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">Боковое меню и дерево</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="none" aria-pressed="false"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="nav" data-panel-pattern="hex" aria-pressed="true"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="nav" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="nav" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="nav" data-panel-pattern-field="height" /><output data-panel-pattern-value="nav" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="nav" data-panel-pattern-field="fade" /><output data-panel-pattern-value="nav" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: прозрачность</span><input type="range" min="0" max="100" step="1" value="80" data-panel-pattern-tuning="nav" data-panel-pattern-field="gradientOpacity" /><output data-panel-pattern-value="nav" data-panel-pattern-field="gradientOpacity">80%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: высота</span><input type="range" min="0" max="100" step="1" value="40" data-panel-pattern-tuning="nav" data-panel-pattern-field="gradientHeight" /><output data-panel-pattern-value="nav" data-panel-pattern-field="gradientHeight">40%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: переход</span><input type="range" min="0" max="100" step="1" value="8" data-panel-pattern-tuning="nav" data-panel-pattern-field="gradientFade" /><output data-panel-pattern-value="nav" data-panel-pattern-field="gradientFade">8%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="section">
|
||||||
|
<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">Карточки верхнего уровня каталога</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="none" aria-pressed="false"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="section" data-panel-pattern="hex" aria-pressed="true"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="section" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="section" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="section" data-panel-pattern-field="height" /><output data-panel-pattern-value="section" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="section" data-panel-pattern-field="fade" /><output data-panel-pattern-value="section" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: прозрачность</span><input type="range" min="0" max="100" step="1" value="80" data-panel-pattern-tuning="section" data-panel-pattern-field="gradientOpacity" /><output data-panel-pattern-value="section" data-panel-pattern-field="gradientOpacity">80%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: высота</span><input type="range" min="0" max="100" step="1" value="40" data-panel-pattern-tuning="section" data-panel-pattern-field="gradientHeight" /><output data-panel-pattern-value="section" data-panel-pattern-field="gradientHeight">40%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: переход</span><input type="range" min="0" max="100" step="1" value="8" data-panel-pattern-tuning="section" data-panel-pattern-field="gradientFade" /><output data-panel-pattern-value="section" data-panel-pattern-field="gradientFade">8%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="group">
|
||||||
|
<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">Группы внутри раздела</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="group" data-panel-pattern="none" aria-pressed="true"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="hex" aria-pressed="false"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="group" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="group" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="group" data-panel-pattern-field="height" /><output data-panel-pattern-value="group" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="group" data-panel-pattern-field="fade" /><output data-panel-pattern-value="group" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: прозрачность</span><input type="range" min="0" max="100" step="1" value="80" data-panel-pattern-tuning="group" data-panel-pattern-field="gradientOpacity" /><output data-panel-pattern-value="group" data-panel-pattern-field="gradientOpacity">80%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: высота</span><input type="range" min="0" max="100" step="1" value="40" data-panel-pattern-tuning="group" data-panel-pattern-field="gradientHeight" /><output data-panel-pattern-value="group" data-panel-pattern-field="gradientHeight">40%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: переход</span><input type="range" min="0" max="100" step="1" value="8" data-panel-pattern-tuning="group" data-panel-pattern-field="gradientFade" /><output data-panel-pattern-value="group" data-panel-pattern-field="gradientFade">8%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="item">
|
||||||
|
<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">Карточки сервисов — только узор, без акцентного градиента</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="item" data-panel-pattern="none" aria-pressed="true"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="hex" aria-pressed="false"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="item" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="item" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="item" data-panel-pattern-field="height" /><output data-panel-pattern-value="item" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="item" data-panel-pattern-field="fade" /><output data-panel-pattern-value="item" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Настройки пользовательского linear-gradient акцента. -->
|
<!-- Настройки пользовательского linear-gradient акцента. -->
|
||||||
<div class="accent-custom-panel" data-accent-custom-panel data-feature="allowAccentChange" hidden>
|
<div class="accent-custom-panel" data-accent-custom-panel data-feature="allowAccentChange" hidden>
|
||||||
<p class="accent-custom-title">Свой градиент</p>
|
<p class="accent-custom-title">Свой градиент</p>
|
||||||
|
|||||||
@ -11,6 +11,26 @@
|
|||||||
"customAccentFrom": "#8b5cf6",
|
"customAccentFrom": "#8b5cf6",
|
||||||
"customAccentTo": "#22d3ee",
|
"customAccentTo": "#22d3ee",
|
||||||
"customAccentAngle": 135,
|
"customAccentAngle": 135,
|
||||||
|
"panelPatternNav": "hex",
|
||||||
|
"panelPatternNavOpacity": 70,
|
||||||
|
"panelPatternNavHeight": 45,
|
||||||
|
"panelPatternNavGradientOpacity": 80,
|
||||||
|
"panelPatternNavGradientHeight": 40,
|
||||||
|
"panelPatternSection": "hex",
|
||||||
|
"panelPatternSectionOpacity": 70,
|
||||||
|
"panelPatternSectionHeight": 45,
|
||||||
|
"panelPatternSectionGradientOpacity": 80,
|
||||||
|
"panelPatternSectionGradientHeight": 40,
|
||||||
|
"panelPatternGroup": "none",
|
||||||
|
"panelPatternGroupOpacity": 70,
|
||||||
|
"panelPatternGroupHeight": 45,
|
||||||
|
"panelPatternGroupGradientOpacity": 80,
|
||||||
|
"panelPatternGroupGradientHeight": 40,
|
||||||
|
"panelPatternItem": "none",
|
||||||
|
"panelPatternItemOpacity": 70,
|
||||||
|
"panelPatternItemHeight": 45,
|
||||||
|
"panelPatternItemGradientOpacity": 80,
|
||||||
|
"panelPatternItemGradientHeight": 40,
|
||||||
"showNumbers": false,
|
"showNumbers": false,
|
||||||
"showTreeTags": true,
|
"showTreeTags": true,
|
||||||
"showTreeType": false,
|
"showTreeType": false,
|
||||||
@ -31,7 +51,8 @@
|
|||||||
"catalogListColumns": 1,
|
"catalogListColumns": 1,
|
||||||
"catalogCompactCardsColumns": 5,
|
"catalogCompactCardsColumns": 5,
|
||||||
"catalogCompactListColumns": 3,
|
"catalogCompactListColumns": 3,
|
||||||
"searchPlaceholder": "Grafana, S3, журнал, сервер..."
|
"searchPlaceholder": "Grafana, S3, журнал, сервер...",
|
||||||
|
"settingsPanelWidth": 460
|
||||||
},
|
},
|
||||||
"limits": {
|
"limits": {
|
||||||
"shellMaxWidth": { "min": 1200, "max": 3840 },
|
"shellMaxWidth": { "min": 1200, "max": 3840 },
|
||||||
@ -45,7 +66,8 @@
|
|||||||
"catalogCardsColumns": { "min": 1, "max": 6 },
|
"catalogCardsColumns": { "min": 1, "max": 6 },
|
||||||
"catalogListColumns": { "min": 1, "max": 4 },
|
"catalogListColumns": { "min": 1, "max": 4 },
|
||||||
"catalogCompactCardsColumns": { "min": 2, "max": 8 },
|
"catalogCompactCardsColumns": { "min": 2, "max": 8 },
|
||||||
"catalogCompactListColumns": { "min": 1, "max": 6 }
|
"catalogCompactListColumns": { "min": 1, "max": 6 },
|
||||||
|
"settingsPanelWidth": { "min": 320, "max": 720 }
|
||||||
},
|
},
|
||||||
"features": {
|
"features": {
|
||||||
"allowNavLayoutChange": true,
|
"allowNavLayoutChange": true,
|
||||||
@ -58,6 +80,7 @@
|
|||||||
"allowSidebarResize": true,
|
"allowSidebarResize": true,
|
||||||
"allowLayoutLimitsChange": true,
|
"allowLayoutLimitsChange": true,
|
||||||
"allowThemeChange": true,
|
"allowThemeChange": true,
|
||||||
"allowAccentChange": true
|
"allowAccentChange": true,
|
||||||
|
"allowPanelPatternChange": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -126,6 +126,11 @@
|
|||||||
</span>
|
</span>
|
||||||
<input type="checkbox" data-show-resize-handles checked />
|
<input type="checkbox" data-show-resize-handles checked />
|
||||||
</label>
|
</label>
|
||||||
|
<label class="accent-custom-row settings-width-row">
|
||||||
|
<span>Ширина настроек</span>
|
||||||
|
<input type="range" data-settings-panel-width />
|
||||||
|
<output data-settings-panel-width-value>460px</output>
|
||||||
|
</label>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<details class="settings-section settings-section-collapsible" data-settings-section="dimensions">
|
<details class="settings-section settings-section-collapsible" data-settings-section="dimensions">
|
||||||
@ -368,6 +373,114 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="pattern-targets-panel" data-pattern-targets-panel data-feature="allowPanelPatternChange">
|
||||||
|
<p class="settings-section-hint">Узор и градиент настраиваются отдельно для каждого типа блоков.</p>
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="nav">
|
||||||
|
<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">Боковое меню и дерево</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="none" aria-pressed="false"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="nav" data-panel-pattern="hex" aria-pressed="true"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="nav" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="nav" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="nav" data-panel-pattern-field="height" /><output data-panel-pattern-value="nav" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="nav" data-panel-pattern-field="fade" /><output data-panel-pattern-value="nav" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: прозрачность</span><input type="range" min="0" max="100" step="1" value="80" data-panel-pattern-tuning="nav" data-panel-pattern-field="gradientOpacity" /><output data-panel-pattern-value="nav" data-panel-pattern-field="gradientOpacity">80%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: высота</span><input type="range" min="0" max="100" step="1" value="40" data-panel-pattern-tuning="nav" data-panel-pattern-field="gradientHeight" /><output data-panel-pattern-value="nav" data-panel-pattern-field="gradientHeight">40%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: переход</span><input type="range" min="0" max="100" step="1" value="8" data-panel-pattern-tuning="nav" data-panel-pattern-field="gradientFade" /><output data-panel-pattern-value="nav" data-panel-pattern-field="gradientFade">8%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="section">
|
||||||
|
<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">Карточки верхнего уровня каталога</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="none" aria-pressed="false"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="section" data-panel-pattern="hex" aria-pressed="true"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="section" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="section" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="section" data-panel-pattern-field="height" /><output data-panel-pattern-value="section" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="section" data-panel-pattern-field="fade" /><output data-panel-pattern-value="section" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: прозрачность</span><input type="range" min="0" max="100" step="1" value="80" data-panel-pattern-tuning="section" data-panel-pattern-field="gradientOpacity" /><output data-panel-pattern-value="section" data-panel-pattern-field="gradientOpacity">80%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: высота</span><input type="range" min="0" max="100" step="1" value="40" data-panel-pattern-tuning="section" data-panel-pattern-field="gradientHeight" /><output data-panel-pattern-value="section" data-panel-pattern-field="gradientHeight">40%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: переход</span><input type="range" min="0" max="100" step="1" value="8" data-panel-pattern-tuning="section" data-panel-pattern-field="gradientFade" /><output data-panel-pattern-value="section" data-panel-pattern-field="gradientFade">8%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="group">
|
||||||
|
<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">Группы внутри раздела</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="group" data-panel-pattern="none" aria-pressed="true"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="hex" aria-pressed="false"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="group" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="group" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="group" data-panel-pattern-field="height" /><output data-panel-pattern-value="group" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="group" data-panel-pattern-field="fade" /><output data-panel-pattern-value="group" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: прозрачность</span><input type="range" min="0" max="100" step="1" value="80" data-panel-pattern-tuning="group" data-panel-pattern-field="gradientOpacity" /><output data-panel-pattern-value="group" data-panel-pattern-field="gradientOpacity">80%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: высота</span><input type="range" min="0" max="100" step="1" value="40" data-panel-pattern-tuning="group" data-panel-pattern-field="gradientHeight" /><output data-panel-pattern-value="group" data-panel-pattern-field="gradientHeight">40%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: переход</span><input type="range" min="0" max="100" step="1" value="8" data-panel-pattern-tuning="group" data-panel-pattern-field="gradientFade" /><output data-panel-pattern-value="group" data-panel-pattern-field="gradientFade">8%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="item">
|
||||||
|
<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">Карточки сервисов — только узор, без акцентного градиента</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="item" data-panel-pattern="none" aria-pressed="true"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="hex" aria-pressed="false"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="item" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="item" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="item" data-panel-pattern-field="height" /><output data-panel-pattern-value="item" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="item" data-panel-pattern-field="fade" /><output data-panel-pattern-value="item" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Настройки пользовательского linear-gradient акцента. -->
|
<!-- Настройки пользовательского linear-gradient акцента. -->
|
||||||
<div class="accent-custom-panel" data-accent-custom-panel data-feature="allowAccentChange" hidden>
|
<div class="accent-custom-panel" data-accent-custom-panel data-feature="allowAccentChange" hidden>
|
||||||
<p class="accent-custom-title">Свой градиент</p>
|
<p class="accent-custom-title">Свой градиент</p>
|
||||||
|
|||||||
@ -11,6 +11,26 @@
|
|||||||
"customAccentFrom": "#8b5cf6",
|
"customAccentFrom": "#8b5cf6",
|
||||||
"customAccentTo": "#22d3ee",
|
"customAccentTo": "#22d3ee",
|
||||||
"customAccentAngle": 135,
|
"customAccentAngle": 135,
|
||||||
|
"panelPatternNav": "hex",
|
||||||
|
"panelPatternNavOpacity": 70,
|
||||||
|
"panelPatternNavHeight": 45,
|
||||||
|
"panelPatternNavGradientOpacity": 80,
|
||||||
|
"panelPatternNavGradientHeight": 40,
|
||||||
|
"panelPatternSection": "hex",
|
||||||
|
"panelPatternSectionOpacity": 70,
|
||||||
|
"panelPatternSectionHeight": 45,
|
||||||
|
"panelPatternSectionGradientOpacity": 80,
|
||||||
|
"panelPatternSectionGradientHeight": 40,
|
||||||
|
"panelPatternGroup": "none",
|
||||||
|
"panelPatternGroupOpacity": 70,
|
||||||
|
"panelPatternGroupHeight": 45,
|
||||||
|
"panelPatternGroupGradientOpacity": 80,
|
||||||
|
"panelPatternGroupGradientHeight": 40,
|
||||||
|
"panelPatternItem": "none",
|
||||||
|
"panelPatternItemOpacity": 70,
|
||||||
|
"panelPatternItemHeight": 45,
|
||||||
|
"panelPatternItemGradientOpacity": 80,
|
||||||
|
"panelPatternItemGradientHeight": 40,
|
||||||
"showNumbers": false,
|
"showNumbers": false,
|
||||||
"showTreeTags": true,
|
"showTreeTags": true,
|
||||||
"showTreeType": false,
|
"showTreeType": false,
|
||||||
@ -31,7 +51,8 @@
|
|||||||
"catalogListColumns": 1,
|
"catalogListColumns": 1,
|
||||||
"catalogCompactCardsColumns": 5,
|
"catalogCompactCardsColumns": 5,
|
||||||
"catalogCompactListColumns": 3,
|
"catalogCompactListColumns": 3,
|
||||||
"searchPlaceholder": "Grafana, S3, журнал, сервер..."
|
"searchPlaceholder": "Grafana, S3, журнал, сервер...",
|
||||||
|
"settingsPanelWidth": 460
|
||||||
},
|
},
|
||||||
"limits": {
|
"limits": {
|
||||||
"shellMaxWidth": { "min": 1200, "max": 3840 },
|
"shellMaxWidth": { "min": 1200, "max": 3840 },
|
||||||
@ -45,7 +66,8 @@
|
|||||||
"catalogCardsColumns": { "min": 1, "max": 6 },
|
"catalogCardsColumns": { "min": 1, "max": 6 },
|
||||||
"catalogListColumns": { "min": 1, "max": 4 },
|
"catalogListColumns": { "min": 1, "max": 4 },
|
||||||
"catalogCompactCardsColumns": { "min": 2, "max": 8 },
|
"catalogCompactCardsColumns": { "min": 2, "max": 8 },
|
||||||
"catalogCompactListColumns": { "min": 1, "max": 6 }
|
"catalogCompactListColumns": { "min": 1, "max": 6 },
|
||||||
|
"settingsPanelWidth": { "min": 320, "max": 720 }
|
||||||
},
|
},
|
||||||
"features": {
|
"features": {
|
||||||
"allowNavLayoutChange": true,
|
"allowNavLayoutChange": true,
|
||||||
@ -58,6 +80,7 @@
|
|||||||
"allowSidebarResize": true,
|
"allowSidebarResize": true,
|
||||||
"allowLayoutLimitsChange": true,
|
"allowLayoutLimitsChange": true,
|
||||||
"allowThemeChange": true,
|
"allowThemeChange": true,
|
||||||
"allowAccentChange": true
|
"allowAccentChange": true,
|
||||||
|
"allowPanelPatternChange": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -126,6 +126,11 @@
|
|||||||
</span>
|
</span>
|
||||||
<input type="checkbox" data-show-resize-handles checked />
|
<input type="checkbox" data-show-resize-handles checked />
|
||||||
</label>
|
</label>
|
||||||
|
<label class="accent-custom-row settings-width-row">
|
||||||
|
<span>Ширина настроек</span>
|
||||||
|
<input type="range" data-settings-panel-width />
|
||||||
|
<output data-settings-panel-width-value>460px</output>
|
||||||
|
</label>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<details class="settings-section settings-section-collapsible" data-settings-section="dimensions">
|
<details class="settings-section settings-section-collapsible" data-settings-section="dimensions">
|
||||||
@ -368,6 +373,114 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="pattern-targets-panel" data-pattern-targets-panel data-feature="allowPanelPatternChange">
|
||||||
|
<p class="settings-section-hint">Узор и градиент настраиваются отдельно для каждого типа блоков.</p>
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="nav">
|
||||||
|
<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">Боковое меню и дерево</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="none" aria-pressed="false"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="nav" data-panel-pattern="hex" aria-pressed="true"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="nav" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="nav" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="nav" data-panel-pattern-field="height" /><output data-panel-pattern-value="nav" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="nav" data-panel-pattern-field="fade" /><output data-panel-pattern-value="nav" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: прозрачность</span><input type="range" min="0" max="100" step="1" value="80" data-panel-pattern-tuning="nav" data-panel-pattern-field="gradientOpacity" /><output data-panel-pattern-value="nav" data-panel-pattern-field="gradientOpacity">80%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: высота</span><input type="range" min="0" max="100" step="1" value="40" data-panel-pattern-tuning="nav" data-panel-pattern-field="gradientHeight" /><output data-panel-pattern-value="nav" data-panel-pattern-field="gradientHeight">40%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: переход</span><input type="range" min="0" max="100" step="1" value="8" data-panel-pattern-tuning="nav" data-panel-pattern-field="gradientFade" /><output data-panel-pattern-value="nav" data-panel-pattern-field="gradientFade">8%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="section">
|
||||||
|
<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">Карточки верхнего уровня каталога</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="none" aria-pressed="false"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="section" data-panel-pattern="hex" aria-pressed="true"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="section" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="section" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="section" data-panel-pattern-field="height" /><output data-panel-pattern-value="section" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="section" data-panel-pattern-field="fade" /><output data-panel-pattern-value="section" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: прозрачность</span><input type="range" min="0" max="100" step="1" value="80" data-panel-pattern-tuning="section" data-panel-pattern-field="gradientOpacity" /><output data-panel-pattern-value="section" data-panel-pattern-field="gradientOpacity">80%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: высота</span><input type="range" min="0" max="100" step="1" value="40" data-panel-pattern-tuning="section" data-panel-pattern-field="gradientHeight" /><output data-panel-pattern-value="section" data-panel-pattern-field="gradientHeight">40%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: переход</span><input type="range" min="0" max="100" step="1" value="8" data-panel-pattern-tuning="section" data-panel-pattern-field="gradientFade" /><output data-panel-pattern-value="section" data-panel-pattern-field="gradientFade">8%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="group">
|
||||||
|
<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">Группы внутри раздела</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="group" data-panel-pattern="none" aria-pressed="true"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="hex" aria-pressed="false"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="group" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="group" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="group" data-panel-pattern-field="height" /><output data-panel-pattern-value="group" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="group" data-panel-pattern-field="fade" /><output data-panel-pattern-value="group" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: прозрачность</span><input type="range" min="0" max="100" step="1" value="80" data-panel-pattern-tuning="group" data-panel-pattern-field="gradientOpacity" /><output data-panel-pattern-value="group" data-panel-pattern-field="gradientOpacity">80%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: высота</span><input type="range" min="0" max="100" step="1" value="40" data-panel-pattern-tuning="group" data-panel-pattern-field="gradientHeight" /><output data-panel-pattern-value="group" data-panel-pattern-field="gradientHeight">40%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: переход</span><input type="range" min="0" max="100" step="1" value="8" data-panel-pattern-tuning="group" data-panel-pattern-field="gradientFade" /><output data-panel-pattern-value="group" data-panel-pattern-field="gradientFade">8%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="item">
|
||||||
|
<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">Карточки сервисов — только узор, без акцентного градиента</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="item" data-panel-pattern="none" aria-pressed="true"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="hex" aria-pressed="false"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="item" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="item" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="item" data-panel-pattern-field="height" /><output data-panel-pattern-value="item" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="item" data-panel-pattern-field="fade" /><output data-panel-pattern-value="item" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Настройки пользовательского linear-gradient акцента. -->
|
<!-- Настройки пользовательского linear-gradient акцента. -->
|
||||||
<div class="accent-custom-panel" data-accent-custom-panel data-feature="allowAccentChange" hidden>
|
<div class="accent-custom-panel" data-accent-custom-panel data-feature="allowAccentChange" hidden>
|
||||||
<p class="accent-custom-title">Свой градиент</p>
|
<p class="accent-custom-title">Свой градиент</p>
|
||||||
|
|||||||
@ -11,6 +11,26 @@
|
|||||||
"customAccentFrom": "#8b5cf6",
|
"customAccentFrom": "#8b5cf6",
|
||||||
"customAccentTo": "#22d3ee",
|
"customAccentTo": "#22d3ee",
|
||||||
"customAccentAngle": 135,
|
"customAccentAngle": 135,
|
||||||
|
"panelPatternNav": "hex",
|
||||||
|
"panelPatternNavOpacity": 70,
|
||||||
|
"panelPatternNavHeight": 45,
|
||||||
|
"panelPatternNavGradientOpacity": 80,
|
||||||
|
"panelPatternNavGradientHeight": 40,
|
||||||
|
"panelPatternSection": "hex",
|
||||||
|
"panelPatternSectionOpacity": 70,
|
||||||
|
"panelPatternSectionHeight": 45,
|
||||||
|
"panelPatternSectionGradientOpacity": 80,
|
||||||
|
"panelPatternSectionGradientHeight": 40,
|
||||||
|
"panelPatternGroup": "none",
|
||||||
|
"panelPatternGroupOpacity": 70,
|
||||||
|
"panelPatternGroupHeight": 45,
|
||||||
|
"panelPatternGroupGradientOpacity": 80,
|
||||||
|
"panelPatternGroupGradientHeight": 40,
|
||||||
|
"panelPatternItem": "none",
|
||||||
|
"panelPatternItemOpacity": 70,
|
||||||
|
"panelPatternItemHeight": 45,
|
||||||
|
"panelPatternItemGradientOpacity": 80,
|
||||||
|
"panelPatternItemGradientHeight": 40,
|
||||||
"showNumbers": false,
|
"showNumbers": false,
|
||||||
"showTreeTags": true,
|
"showTreeTags": true,
|
||||||
"showTreeType": false,
|
"showTreeType": false,
|
||||||
@ -31,7 +51,8 @@
|
|||||||
"catalogListColumns": 1,
|
"catalogListColumns": 1,
|
||||||
"catalogCompactCardsColumns": 5,
|
"catalogCompactCardsColumns": 5,
|
||||||
"catalogCompactListColumns": 3,
|
"catalogCompactListColumns": 3,
|
||||||
"searchPlaceholder": "Grafana, S3, журнал, сервер..."
|
"searchPlaceholder": "Grafana, S3, журнал, сервер...",
|
||||||
|
"settingsPanelWidth": 460
|
||||||
},
|
},
|
||||||
"limits": {
|
"limits": {
|
||||||
"shellMaxWidth": { "min": 1200, "max": 3840 },
|
"shellMaxWidth": { "min": 1200, "max": 3840 },
|
||||||
@ -45,7 +66,8 @@
|
|||||||
"catalogCardsColumns": { "min": 1, "max": 6 },
|
"catalogCardsColumns": { "min": 1, "max": 6 },
|
||||||
"catalogListColumns": { "min": 1, "max": 4 },
|
"catalogListColumns": { "min": 1, "max": 4 },
|
||||||
"catalogCompactCardsColumns": { "min": 2, "max": 8 },
|
"catalogCompactCardsColumns": { "min": 2, "max": 8 },
|
||||||
"catalogCompactListColumns": { "min": 1, "max": 6 }
|
"catalogCompactListColumns": { "min": 1, "max": 6 },
|
||||||
|
"settingsPanelWidth": { "min": 320, "max": 720 }
|
||||||
},
|
},
|
||||||
"features": {
|
"features": {
|
||||||
"allowNavLayoutChange": true,
|
"allowNavLayoutChange": true,
|
||||||
@ -58,6 +80,7 @@
|
|||||||
"allowSidebarResize": true,
|
"allowSidebarResize": true,
|
||||||
"allowLayoutLimitsChange": true,
|
"allowLayoutLimitsChange": true,
|
||||||
"allowThemeChange": true,
|
"allowThemeChange": true,
|
||||||
"allowAccentChange": true
|
"allowAccentChange": true,
|
||||||
|
"allowPanelPatternChange": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -126,6 +126,11 @@
|
|||||||
</span>
|
</span>
|
||||||
<input type="checkbox" data-show-resize-handles checked />
|
<input type="checkbox" data-show-resize-handles checked />
|
||||||
</label>
|
</label>
|
||||||
|
<label class="accent-custom-row settings-width-row">
|
||||||
|
<span>Ширина настроек</span>
|
||||||
|
<input type="range" data-settings-panel-width />
|
||||||
|
<output data-settings-panel-width-value>460px</output>
|
||||||
|
</label>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<details class="settings-section settings-section-collapsible" data-settings-section="dimensions">
|
<details class="settings-section settings-section-collapsible" data-settings-section="dimensions">
|
||||||
@ -368,6 +373,114 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="pattern-targets-panel" data-pattern-targets-panel data-feature="allowPanelPatternChange">
|
||||||
|
<p class="settings-section-hint">Узор и градиент настраиваются отдельно для каждого типа блоков.</p>
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="nav">
|
||||||
|
<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">Боковое меню и дерево</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="none" aria-pressed="false"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="nav" data-panel-pattern="hex" aria-pressed="true"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="nav" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="nav" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="nav" data-panel-pattern-field="height" /><output data-panel-pattern-value="nav" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="nav" data-panel-pattern-field="fade" /><output data-panel-pattern-value="nav" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: прозрачность</span><input type="range" min="0" max="100" step="1" value="80" data-panel-pattern-tuning="nav" data-panel-pattern-field="gradientOpacity" /><output data-panel-pattern-value="nav" data-panel-pattern-field="gradientOpacity">80%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: высота</span><input type="range" min="0" max="100" step="1" value="40" data-panel-pattern-tuning="nav" data-panel-pattern-field="gradientHeight" /><output data-panel-pattern-value="nav" data-panel-pattern-field="gradientHeight">40%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: переход</span><input type="range" min="0" max="100" step="1" value="8" data-panel-pattern-tuning="nav" data-panel-pattern-field="gradientFade" /><output data-panel-pattern-value="nav" data-panel-pattern-field="gradientFade">8%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="section">
|
||||||
|
<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">Карточки верхнего уровня каталога</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="none" aria-pressed="false"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="section" data-panel-pattern="hex" aria-pressed="true"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="section" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="section" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="section" data-panel-pattern-field="height" /><output data-panel-pattern-value="section" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="section" data-panel-pattern-field="fade" /><output data-panel-pattern-value="section" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: прозрачность</span><input type="range" min="0" max="100" step="1" value="80" data-panel-pattern-tuning="section" data-panel-pattern-field="gradientOpacity" /><output data-panel-pattern-value="section" data-panel-pattern-field="gradientOpacity">80%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: высота</span><input type="range" min="0" max="100" step="1" value="40" data-panel-pattern-tuning="section" data-panel-pattern-field="gradientHeight" /><output data-panel-pattern-value="section" data-panel-pattern-field="gradientHeight">40%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: переход</span><input type="range" min="0" max="100" step="1" value="8" data-panel-pattern-tuning="section" data-panel-pattern-field="gradientFade" /><output data-panel-pattern-value="section" data-panel-pattern-field="gradientFade">8%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="group">
|
||||||
|
<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">Группы внутри раздела</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="group" data-panel-pattern="none" aria-pressed="true"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="hex" aria-pressed="false"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="group" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="group" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="group" data-panel-pattern-field="height" /><output data-panel-pattern-value="group" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="group" data-panel-pattern-field="fade" /><output data-panel-pattern-value="group" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: прозрачность</span><input type="range" min="0" max="100" step="1" value="80" data-panel-pattern-tuning="group" data-panel-pattern-field="gradientOpacity" /><output data-panel-pattern-value="group" data-panel-pattern-field="gradientOpacity">80%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: высота</span><input type="range" min="0" max="100" step="1" value="40" data-panel-pattern-tuning="group" data-panel-pattern-field="gradientHeight" /><output data-panel-pattern-value="group" data-panel-pattern-field="gradientHeight">40%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: переход</span><input type="range" min="0" max="100" step="1" value="8" data-panel-pattern-tuning="group" data-panel-pattern-field="gradientFade" /><output data-panel-pattern-value="group" data-panel-pattern-field="gradientFade">8%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="item">
|
||||||
|
<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">Карточки сервисов — только узор, без акцентного градиента</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="item" data-panel-pattern="none" aria-pressed="true"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="hex" aria-pressed="false"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="item" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="item" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="item" data-panel-pattern-field="height" /><output data-panel-pattern-value="item" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="item" data-panel-pattern-field="fade" /><output data-panel-pattern-value="item" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Настройки пользовательского linear-gradient акцента. -->
|
<!-- Настройки пользовательского linear-gradient акцента. -->
|
||||||
<div class="accent-custom-panel" data-accent-custom-panel data-feature="allowAccentChange" hidden>
|
<div class="accent-custom-panel" data-accent-custom-panel data-feature="allowAccentChange" hidden>
|
||||||
<p class="accent-custom-title">Свой градиент</p>
|
<p class="accent-custom-title">Свой градиент</p>
|
||||||
|
|||||||
@ -11,6 +11,26 @@
|
|||||||
"customAccentFrom": "#8b5cf6",
|
"customAccentFrom": "#8b5cf6",
|
||||||
"customAccentTo": "#22d3ee",
|
"customAccentTo": "#22d3ee",
|
||||||
"customAccentAngle": 135,
|
"customAccentAngle": 135,
|
||||||
|
"panelPatternNav": "hex",
|
||||||
|
"panelPatternNavOpacity": 70,
|
||||||
|
"panelPatternNavHeight": 45,
|
||||||
|
"panelPatternNavGradientOpacity": 80,
|
||||||
|
"panelPatternNavGradientHeight": 40,
|
||||||
|
"panelPatternSection": "hex",
|
||||||
|
"panelPatternSectionOpacity": 70,
|
||||||
|
"panelPatternSectionHeight": 45,
|
||||||
|
"panelPatternSectionGradientOpacity": 80,
|
||||||
|
"panelPatternSectionGradientHeight": 40,
|
||||||
|
"panelPatternGroup": "none",
|
||||||
|
"panelPatternGroupOpacity": 70,
|
||||||
|
"panelPatternGroupHeight": 45,
|
||||||
|
"panelPatternGroupGradientOpacity": 80,
|
||||||
|
"panelPatternGroupGradientHeight": 40,
|
||||||
|
"panelPatternItem": "none",
|
||||||
|
"panelPatternItemOpacity": 70,
|
||||||
|
"panelPatternItemHeight": 45,
|
||||||
|
"panelPatternItemGradientOpacity": 80,
|
||||||
|
"panelPatternItemGradientHeight": 40,
|
||||||
"showNumbers": false,
|
"showNumbers": false,
|
||||||
"showTreeTags": true,
|
"showTreeTags": true,
|
||||||
"showTreeType": false,
|
"showTreeType": false,
|
||||||
@ -31,7 +51,8 @@
|
|||||||
"catalogListColumns": 1,
|
"catalogListColumns": 1,
|
||||||
"catalogCompactCardsColumns": 5,
|
"catalogCompactCardsColumns": 5,
|
||||||
"catalogCompactListColumns": 3,
|
"catalogCompactListColumns": 3,
|
||||||
"searchPlaceholder": "Grafana, S3, журнал, сервер..."
|
"searchPlaceholder": "Grafana, S3, журнал, сервер...",
|
||||||
|
"settingsPanelWidth": 460
|
||||||
},
|
},
|
||||||
"limits": {
|
"limits": {
|
||||||
"shellMaxWidth": { "min": 1200, "max": 3840 },
|
"shellMaxWidth": { "min": 1200, "max": 3840 },
|
||||||
@ -45,7 +66,8 @@
|
|||||||
"catalogCardsColumns": { "min": 1, "max": 6 },
|
"catalogCardsColumns": { "min": 1, "max": 6 },
|
||||||
"catalogListColumns": { "min": 1, "max": 4 },
|
"catalogListColumns": { "min": 1, "max": 4 },
|
||||||
"catalogCompactCardsColumns": { "min": 2, "max": 8 },
|
"catalogCompactCardsColumns": { "min": 2, "max": 8 },
|
||||||
"catalogCompactListColumns": { "min": 1, "max": 6 }
|
"catalogCompactListColumns": { "min": 1, "max": 6 },
|
||||||
|
"settingsPanelWidth": { "min": 320, "max": 720 }
|
||||||
},
|
},
|
||||||
"features": {
|
"features": {
|
||||||
"allowNavLayoutChange": true,
|
"allowNavLayoutChange": true,
|
||||||
@ -58,6 +80,7 @@
|
|||||||
"allowSidebarResize": true,
|
"allowSidebarResize": true,
|
||||||
"allowLayoutLimitsChange": true,
|
"allowLayoutLimitsChange": true,
|
||||||
"allowThemeChange": true,
|
"allowThemeChange": true,
|
||||||
"allowAccentChange": true
|
"allowAccentChange": true,
|
||||||
|
"allowPanelPatternChange": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,6 +65,44 @@ const defaultServiceMeta = {
|
|||||||
|
|
||||||
let serviceMeta = { ...defaultServiceMeta };
|
let serviceMeta = { ...defaultServiceMeta };
|
||||||
|
|
||||||
|
const availablePanelPatterns = ["none", "hex", "dots", "grid", "diagonal", "cross", "mesh"];
|
||||||
|
const panelPatternTargetIds = ["nav", "section", "group", "item"];
|
||||||
|
const panelPatternTuningDefaults = {
|
||||||
|
opacity: 70,
|
||||||
|
height: 45,
|
||||||
|
fade: 10,
|
||||||
|
gradientOpacity: 80,
|
||||||
|
gradientHeight: 40,
|
||||||
|
gradientFade: 8,
|
||||||
|
};
|
||||||
|
const panelPatternTargetMeta = {
|
||||||
|
nav: { defaultPattern: "hex" },
|
||||||
|
section: { defaultPattern: "hex" },
|
||||||
|
group: { defaultPattern: "none" },
|
||||||
|
item: { defaultPattern: "none" },
|
||||||
|
};
|
||||||
|
|
||||||
|
function capitalizePanelPatternTarget(target) {
|
||||||
|
return target.charAt(0).toUpperCase() + target.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildDefaultPanelPatternPreferences() {
|
||||||
|
const prefs = {};
|
||||||
|
|
||||||
|
for (const target of panelPatternTargetIds) {
|
||||||
|
const cap = capitalizePanelPatternTarget(target);
|
||||||
|
prefs[`panelPattern${cap}`] = panelPatternTargetMeta[target].defaultPattern;
|
||||||
|
prefs[`panelPattern${cap}Opacity`] = panelPatternTuningDefaults.opacity;
|
||||||
|
prefs[`panelPattern${cap}Height`] = panelPatternTuningDefaults.height;
|
||||||
|
prefs[`panelPattern${cap}Fade`] = panelPatternTuningDefaults.fade;
|
||||||
|
prefs[`panelPattern${cap}GradientOpacity`] = panelPatternTuningDefaults.gradientOpacity;
|
||||||
|
prefs[`panelPattern${cap}GradientHeight`] = panelPatternTuningDefaults.gradientHeight;
|
||||||
|
prefs[`panelPattern${cap}GradientFade`] = panelPatternTuningDefaults.gradientFade;
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefs;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Default UI preferences
|
// Default UI preferences
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -76,6 +114,7 @@ const defaultPreferences = {
|
|||||||
customAccentFrom: "#8b5cf6",
|
customAccentFrom: "#8b5cf6",
|
||||||
customAccentTo: "#22d3ee",
|
customAccentTo: "#22d3ee",
|
||||||
customAccentAngle: 135,
|
customAccentAngle: 135,
|
||||||
|
...buildDefaultPanelPatternPreferences(),
|
||||||
navLayout: "sidebar",
|
navLayout: "sidebar",
|
||||||
showTree: true,
|
showTree: true,
|
||||||
showResizeHandles: true,
|
showResizeHandles: true,
|
||||||
@ -100,6 +139,7 @@ const defaultPreferences = {
|
|||||||
catalogCompactCardsColumns: 5,
|
catalogCompactCardsColumns: 5,
|
||||||
catalogCompactListColumns: 3,
|
catalogCompactListColumns: 3,
|
||||||
searchPlaceholder: "Grafana, S3, журнал, сервер...",
|
searchPlaceholder: "Grafana, S3, журнал, сервер...",
|
||||||
|
settingsPanelWidth: 460,
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultPanelFeatures = {
|
const defaultPanelFeatures = {
|
||||||
@ -114,6 +154,7 @@ const defaultPanelFeatures = {
|
|||||||
allowLayoutLimitsChange: true,
|
allowLayoutLimitsChange: true,
|
||||||
allowThemeChange: true,
|
allowThemeChange: true,
|
||||||
allowAccentChange: true,
|
allowAccentChange: true,
|
||||||
|
allowPanelPatternChange: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultPanelLimits = {
|
const defaultPanelLimits = {
|
||||||
@ -129,6 +170,7 @@ const defaultPanelLimits = {
|
|||||||
catalogListColumns: { min: 1, max: 4 },
|
catalogListColumns: { min: 1, max: 4 },
|
||||||
catalogCompactCardsColumns: { min: 2, max: 8 },
|
catalogCompactCardsColumns: { min: 2, max: 8 },
|
||||||
catalogCompactListColumns: { min: 1, max: 6 },
|
catalogCompactListColumns: { min: 1, max: 6 },
|
||||||
|
settingsPanelWidth: { min: 320, max: 720 },
|
||||||
};
|
};
|
||||||
|
|
||||||
const layoutLimitKeys = [
|
const layoutLimitKeys = [
|
||||||
@ -149,7 +191,7 @@ const catalogColumnKeys = [
|
|||||||
"catalogCompactListColumns",
|
"catalogCompactListColumns",
|
||||||
];
|
];
|
||||||
|
|
||||||
const panelLimitKeys = [...layoutLimitKeys, ...catalogColumnKeys];
|
const panelLimitKeys = [...layoutLimitKeys, ...catalogColumnKeys, "settingsPanelWidth"];
|
||||||
|
|
||||||
const availableNavLayouts = ["sidebar", "top"];
|
const availableNavLayouts = ["sidebar", "top"];
|
||||||
const availableTreeMetaLayouts = ["inline", "stacked"];
|
const availableTreeMetaLayouts = ["inline", "stacked"];
|
||||||
@ -186,6 +228,7 @@ const themeButtons = document.querySelectorAll("[data-theme]");
|
|||||||
const navLayoutButtons = document.querySelectorAll("[data-nav-layout]");
|
const navLayoutButtons = document.querySelectorAll("[data-nav-layout]");
|
||||||
const viewButtons = document.querySelectorAll("[data-view]");
|
const viewButtons = document.querySelectorAll("[data-view]");
|
||||||
const accentButtons = document.querySelectorAll("[data-accent]");
|
const accentButtons = document.querySelectorAll("[data-accent]");
|
||||||
|
const patternTargetsPanel = document.querySelector("[data-pattern-targets-panel]");
|
||||||
const accentCustomPanel = document.querySelector("[data-accent-custom-panel]");
|
const accentCustomPanel = document.querySelector("[data-accent-custom-panel]");
|
||||||
const customAccentFromInput = document.querySelector("[data-custom-accent-from]");
|
const customAccentFromInput = document.querySelector("[data-custom-accent-from]");
|
||||||
const customAccentToInput = document.querySelector("[data-custom-accent-to]");
|
const customAccentToInput = document.querySelector("[data-custom-accent-to]");
|
||||||
@ -201,6 +244,8 @@ const treeColumnsInput = document.querySelector("[data-tree-columns]");
|
|||||||
const treeColumnsValue = document.querySelector("[data-tree-columns-value]");
|
const treeColumnsValue = document.querySelector("[data-tree-columns-value]");
|
||||||
const treeMetaLayoutButtons = document.querySelectorAll("[data-tree-meta-layout]");
|
const treeMetaLayoutButtons = document.querySelectorAll("[data-tree-meta-layout]");
|
||||||
const autoCollapseSearchInput = document.querySelector("[data-auto-collapse-search]");
|
const autoCollapseSearchInput = document.querySelector("[data-auto-collapse-search]");
|
||||||
|
const settingsPanelWidthInput = document.querySelector("[data-settings-panel-width]");
|
||||||
|
const settingsPanelWidthValue = document.querySelector("[data-settings-panel-width-value]");
|
||||||
const layoutLimitInputs = document.querySelectorAll("[data-layout-limit]");
|
const layoutLimitInputs = document.querySelectorAll("[data-layout-limit]");
|
||||||
const catalogColumnInputs = document.querySelectorAll("[data-catalog-columns]");
|
const catalogColumnInputs = document.querySelectorAll("[data-catalog-columns]");
|
||||||
const settingsSections = document.querySelectorAll("[data-settings-section]");
|
const settingsSections = document.querySelectorAll("[data-settings-section]");
|
||||||
@ -388,6 +433,35 @@ accentButtons.forEach((button) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
patternTargetsPanel?.addEventListener("click", (event) => {
|
||||||
|
const button = event.target.closest("[data-panel-pattern-target][data-panel-pattern]");
|
||||||
|
|
||||||
|
if (!button || !panelFeatures.allowPanelPatternChange) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const target = button.dataset.panelPatternTarget;
|
||||||
|
preferences[getPanelPatternPreferenceKey(target, "pattern")] = button.dataset.panelPattern;
|
||||||
|
applyPreferences(preferences);
|
||||||
|
savePreferences(preferences);
|
||||||
|
});
|
||||||
|
|
||||||
|
patternTargetsPanel?.addEventListener("input", (event) => {
|
||||||
|
const input = event.target.closest("[data-panel-pattern-tuning]");
|
||||||
|
|
||||||
|
if (!input || !panelFeatures.allowPanelPatternChange) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const target = input.dataset.panelPatternTuning;
|
||||||
|
const field = input.dataset.panelPatternField;
|
||||||
|
const key = getPanelPatternPreferenceKey(target, field);
|
||||||
|
const fallback = defaultPreferences[key] ?? panelPatternTuningDefaults[field] ?? 50;
|
||||||
|
preferences[key] = clampPanelPatternPercent(input.value, fallback);
|
||||||
|
applyPreferences(preferences);
|
||||||
|
savePreferences(preferences);
|
||||||
|
});
|
||||||
|
|
||||||
// Изменение параметров своего градиента сразу переключает accent на custom.
|
// Изменение параметров своего градиента сразу переключает accent на custom.
|
||||||
function handleCustomAccentChange() {
|
function handleCustomAccentChange() {
|
||||||
if (!panelFeatures.allowAccentChange) {
|
if (!panelFeatures.allowAccentChange) {
|
||||||
@ -459,6 +533,17 @@ if (treeColumnsInput) {
|
|||||||
treeColumnsInput.addEventListener("input", handleTreeColumnsChange);
|
treeColumnsInput.addEventListener("input", handleTreeColumnsChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSettingsPanelWidthChange() {
|
||||||
|
preferences.settingsPanelWidth = clampLayoutPreference(
|
||||||
|
"settingsPanelWidth",
|
||||||
|
settingsPanelWidthInput?.value,
|
||||||
|
);
|
||||||
|
applyPreferences(preferences);
|
||||||
|
savePreferences(preferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
settingsPanelWidthInput?.addEventListener("input", handleSettingsPanelWidthChange);
|
||||||
|
|
||||||
treeMetaLayoutButtons.forEach((button) => {
|
treeMetaLayoutButtons.forEach((button) => {
|
||||||
button.addEventListener("click", () => {
|
button.addEventListener("click", () => {
|
||||||
if (!panelFeatures.allowTreeOptions || !isTreeVisible(preferences)) {
|
if (!panelFeatures.allowTreeOptions || !isTreeVisible(preferences)) {
|
||||||
@ -625,6 +710,9 @@ function normalizePreferences(raw) {
|
|||||||
next.accent = defaultPreferences.accent;
|
next.accent = defaultPreferences.accent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
migrateLegacyPanelPatternPreferences(next);
|
||||||
|
normalizePanelPatternPreferences(next);
|
||||||
|
|
||||||
if (!availableNavLayouts.includes(next.navLayout)) {
|
if (!availableNavLayouts.includes(next.navLayout)) {
|
||||||
next.navLayout = defaultPreferences.navLayout;
|
next.navLayout = defaultPreferences.navLayout;
|
||||||
}
|
}
|
||||||
@ -659,6 +747,7 @@ function normalizePreferences(raw) {
|
|||||||
getTopBarMinHeight(next),
|
getTopBarMinHeight(next),
|
||||||
getTopBarMaxHeight(next),
|
getTopBarMaxHeight(next),
|
||||||
);
|
);
|
||||||
|
next.settingsPanelWidth = clampLayoutPreference("settingsPanelWidth", next.settingsPanelWidth);
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
@ -724,6 +813,19 @@ function enforceFeatureLocks(rawPreferences) {
|
|||||||
next.customAccentAngle = panelDefaults.customAccentAngle;
|
next.customAccentAngle = panelDefaults.customAccentAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!panelFeatures.allowPanelPatternChange) {
|
||||||
|
for (const target of panelPatternTargetIds) {
|
||||||
|
const cap = capitalizePanelPatternTarget(target);
|
||||||
|
next[`panelPattern${cap}`] = panelDefaults[`panelPattern${cap}`];
|
||||||
|
next[`panelPattern${cap}Opacity`] = panelDefaults[`panelPattern${cap}Opacity`];
|
||||||
|
next[`panelPattern${cap}Height`] = panelDefaults[`panelPattern${cap}Height`];
|
||||||
|
next[`panelPattern${cap}Fade`] = panelDefaults[`panelPattern${cap}Fade`];
|
||||||
|
next[`panelPattern${cap}GradientOpacity`] = panelDefaults[`panelPattern${cap}GradientOpacity`];
|
||||||
|
next[`panelPattern${cap}GradientHeight`] = panelDefaults[`panelPattern${cap}GradientHeight`];
|
||||||
|
next[`panelPattern${cap}GradientFade`] = panelDefaults[`panelPattern${cap}GradientFade`];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!panelFeatures.allowShowNumbers) {
|
if (!panelFeatures.allowShowNumbers) {
|
||||||
next.showNumbers = panelDefaults.showNumbers;
|
next.showNumbers = panelDefaults.showNumbers;
|
||||||
}
|
}
|
||||||
@ -1370,6 +1472,7 @@ function applyPreferences(nextPreferences) {
|
|||||||
|
|
||||||
document.documentElement.dataset.theme = activePreferences.theme;
|
document.documentElement.dataset.theme = activePreferences.theme;
|
||||||
document.documentElement.dataset.accent = activePreferences.accent;
|
document.documentElement.dataset.accent = activePreferences.accent;
|
||||||
|
applyPanelPatternPreferences(activePreferences);
|
||||||
document.documentElement.dataset.navLayout =
|
document.documentElement.dataset.navLayout =
|
||||||
activePreferences.navLayout === "top" ? "top" : "sidebar";
|
activePreferences.navLayout === "top" ? "top" : "sidebar";
|
||||||
document.documentElement.dataset.showTree = String(isTreeVisible(activePreferences));
|
document.documentElement.dataset.showTree = String(isTreeVisible(activePreferences));
|
||||||
@ -1391,6 +1494,10 @@ function applyPreferences(nextPreferences) {
|
|||||||
getTopBarMaxHeight(activePreferences),
|
getTopBarMaxHeight(activePreferences),
|
||||||
)}px`,
|
)}px`,
|
||||||
);
|
);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
"--settings-panel-width",
|
||||||
|
`${clampLayoutPreference("settingsPanelWidth", activePreferences.settingsPanelWidth)}px`,
|
||||||
|
);
|
||||||
const treeColumns = getTreeColumns(activePreferences);
|
const treeColumns = getTreeColumns(activePreferences);
|
||||||
const sidebarMaxWidth = getSidebarMaxWidth(activePreferences);
|
const sidebarMaxWidth = getSidebarMaxWidth(activePreferences);
|
||||||
|
|
||||||
@ -1461,9 +1568,11 @@ function applyPreferences(nextPreferences) {
|
|||||||
setActiveButton(navLayoutButtons, "navLayout", activePreferences.navLayout);
|
setActiveButton(navLayoutButtons, "navLayout", activePreferences.navLayout);
|
||||||
setActiveButton(viewButtons, "view", activePreferences.view);
|
setActiveButton(viewButtons, "view", activePreferences.view);
|
||||||
setActiveButton(accentButtons, "accent", activePreferences.accent);
|
setActiveButton(accentButtons, "accent", activePreferences.accent);
|
||||||
|
syncPatternTargetPanels(activePreferences);
|
||||||
setActiveButton(treeMetaLayoutButtons, "treeMetaLayout", activePreferences.treeMetaLayout);
|
setActiveButton(treeMetaLayoutButtons, "treeMetaLayout", activePreferences.treeMetaLayout);
|
||||||
syncLayoutLimitInputs(activePreferences);
|
syncLayoutLimitInputs(activePreferences);
|
||||||
syncCatalogColumnInputs(activePreferences);
|
syncCatalogColumnInputs(activePreferences);
|
||||||
|
syncSettingsPanelWidthInput(activePreferences);
|
||||||
applyPanelFeatures(activePreferences);
|
applyPanelFeatures(activePreferences);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1524,7 +1633,11 @@ function isSettingsSectionVisible(sectionName, activePreferences) {
|
|||||||
case "tree":
|
case "tree":
|
||||||
return panelFeatures.allowTreeOptions && activePreferences.showTree;
|
return panelFeatures.allowTreeOptions && activePreferences.showTree;
|
||||||
case "appearance":
|
case "appearance":
|
||||||
return panelFeatures.allowThemeChange || panelFeatures.allowAccentChange;
|
return (
|
||||||
|
panelFeatures.allowThemeChange ||
|
||||||
|
panelFeatures.allowAccentChange ||
|
||||||
|
panelFeatures.allowPanelPatternChange
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1776,6 +1889,22 @@ function syncLayoutLimitInputs(activePreferences) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function syncSettingsPanelWidthInput(activePreferences) {
|
||||||
|
if (!settingsPanelWidthInput) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const limits = getPanelLimitRange("settingsPanelWidth");
|
||||||
|
settingsPanelWidthInput.min = String(limits.min);
|
||||||
|
settingsPanelWidthInput.max = String(limits.max);
|
||||||
|
settingsPanelWidthInput.step = "10";
|
||||||
|
settingsPanelWidthInput.value = String(activePreferences.settingsPanelWidth);
|
||||||
|
|
||||||
|
if (settingsPanelWidthValue) {
|
||||||
|
settingsPanelWidthValue.textContent = `${activePreferences.settingsPanelWidth}px`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function syncCatalogColumnInputs(activePreferences) {
|
function syncCatalogColumnInputs(activePreferences) {
|
||||||
catalogColumnInputs.forEach((input) => {
|
catalogColumnInputs.forEach((input) => {
|
||||||
const key = input.dataset.catalogColumns;
|
const key = input.dataset.catalogColumns;
|
||||||
@ -1802,6 +1931,194 @@ function getPanelLimitRange(key) {
|
|||||||
return getLayoutLimitRange(key);
|
return getLayoutLimitRange(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clampPanelPatternPercent(value, fallback = 50) {
|
||||||
|
const numeric = Number(value);
|
||||||
|
const base = Number.isFinite(numeric) ? numeric : fallback;
|
||||||
|
return clamp(Math.round(base), 0, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPanelPatternPreferenceKey(target, field) {
|
||||||
|
const cap = capitalizePanelPatternTarget(target);
|
||||||
|
|
||||||
|
switch (field) {
|
||||||
|
case "pattern":
|
||||||
|
return `panelPattern${cap}`;
|
||||||
|
case "opacity":
|
||||||
|
return `panelPattern${cap}Opacity`;
|
||||||
|
case "height":
|
||||||
|
return `panelPattern${cap}Height`;
|
||||||
|
case "fade":
|
||||||
|
return `panelPattern${cap}Fade`;
|
||||||
|
case "gradientOpacity":
|
||||||
|
return `panelPattern${cap}GradientOpacity`;
|
||||||
|
case "gradientHeight":
|
||||||
|
return `panelPattern${cap}GradientHeight`;
|
||||||
|
case "gradientFade":
|
||||||
|
return `panelPattern${cap}GradientFade`;
|
||||||
|
default:
|
||||||
|
return `panelPattern${cap}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function migrateLegacyPanelPatternPreferences(next) {
|
||||||
|
if (next.panelPatternNav !== undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const legacyPattern = availablePanelPatterns.includes(next.panelPattern)
|
||||||
|
? next.panelPattern
|
||||||
|
: panelPatternTargetMeta.nav.defaultPattern;
|
||||||
|
const legacyOpacity = next.panelPatternOpacity ?? panelPatternTuningDefaults.opacity;
|
||||||
|
const legacyHeight = next.panelPatternHeight ?? panelPatternTuningDefaults.height;
|
||||||
|
const legacyGradientOpacity = next.panelGradientOpacity ?? panelPatternTuningDefaults.gradientOpacity;
|
||||||
|
const legacyGradientHeight = next.panelGradientHeight ?? panelPatternTuningDefaults.gradientHeight;
|
||||||
|
const legacyTargets = [
|
||||||
|
["Nav", next.panelPatternOnNav !== false],
|
||||||
|
["Section", next.panelPatternOnSection !== false],
|
||||||
|
["Group", Boolean(next.panelPatternOnGroup)],
|
||||||
|
["Item", Boolean(next.panelPatternOnItem)],
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const [suffix, enabled] of legacyTargets) {
|
||||||
|
next[`panelPattern${suffix}`] = enabled && legacyPattern !== "none" ? legacyPattern : "none";
|
||||||
|
next[`panelPattern${suffix}Opacity`] = legacyOpacity;
|
||||||
|
next[`panelPattern${suffix}Height`] = legacyHeight;
|
||||||
|
next[`panelPattern${suffix}Fade`] = panelPatternTuningDefaults.fade;
|
||||||
|
next[`panelPattern${suffix}GradientOpacity`] = legacyGradientOpacity;
|
||||||
|
next[`panelPattern${suffix}GradientHeight`] = legacyGradientHeight;
|
||||||
|
next[`panelPattern${suffix}GradientFade`] = panelPatternTuningDefaults.gradientFade;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizePanelPatternPreferences(next) {
|
||||||
|
for (const target of panelPatternTargetIds) {
|
||||||
|
const cap = capitalizePanelPatternTarget(target);
|
||||||
|
const patternKey = `panelPattern${cap}`;
|
||||||
|
|
||||||
|
if (!availablePanelPatterns.includes(next[patternKey])) {
|
||||||
|
next[patternKey] = panelPatternTargetMeta[target].defaultPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
next[`panelPattern${cap}Opacity`] = clampPanelPatternPercent(
|
||||||
|
next[`panelPattern${cap}Opacity`],
|
||||||
|
panelPatternTuningDefaults.opacity,
|
||||||
|
);
|
||||||
|
next[`panelPattern${cap}Height`] = clampPanelPatternPercent(
|
||||||
|
next[`panelPattern${cap}Height`],
|
||||||
|
panelPatternTuningDefaults.height,
|
||||||
|
);
|
||||||
|
next[`panelPattern${cap}Fade`] = clampPanelPatternPercent(
|
||||||
|
next[`panelPattern${cap}Fade`],
|
||||||
|
panelPatternTuningDefaults.fade,
|
||||||
|
);
|
||||||
|
next[`panelPattern${cap}GradientOpacity`] = clampPanelPatternPercent(
|
||||||
|
next[`panelPattern${cap}GradientOpacity`],
|
||||||
|
panelPatternTuningDefaults.gradientOpacity,
|
||||||
|
);
|
||||||
|
next[`panelPattern${cap}GradientHeight`] = clampPanelPatternPercent(
|
||||||
|
next[`panelPattern${cap}GradientHeight`],
|
||||||
|
panelPatternTuningDefaults.gradientHeight,
|
||||||
|
);
|
||||||
|
next[`panelPattern${cap}GradientFade`] = clampPanelPatternPercent(
|
||||||
|
next[`panelPattern${cap}GradientFade`],
|
||||||
|
panelPatternTuningDefaults.gradientFade,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPanelPatternFadeStart(heightPercent, fadePercent) {
|
||||||
|
const height = clampPanelPatternPercent(heightPercent, panelPatternTuningDefaults.height);
|
||||||
|
const fade = clampPanelPatternPercent(fadePercent, panelPatternTuningDefaults.fade);
|
||||||
|
return `${Math.max(0, height - fade)}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyPanelPatternPreferences(activePreferences) {
|
||||||
|
for (const target of panelPatternTargetIds) {
|
||||||
|
const cap = capitalizePanelPatternTarget(target);
|
||||||
|
const pattern = activePreferences[`panelPattern${cap}`] || "none";
|
||||||
|
const height = clampPanelPatternPercent(
|
||||||
|
activePreferences[`panelPattern${cap}Height`],
|
||||||
|
panelPatternTuningDefaults.height,
|
||||||
|
);
|
||||||
|
const opacityPercent = clampPanelPatternPercent(
|
||||||
|
activePreferences[`panelPattern${cap}Opacity`],
|
||||||
|
panelPatternTuningDefaults.opacity,
|
||||||
|
);
|
||||||
|
const patternOpacity = pattern === "none" || height === 0 ? 0 : opacityPercent / 100;
|
||||||
|
|
||||||
|
document.documentElement.dataset[`panelPattern${cap}`] = pattern;
|
||||||
|
document.documentElement.style.setProperty(`--panel-pattern-${target}-opacity`, String(patternOpacity));
|
||||||
|
document.documentElement.style.setProperty(`--panel-pattern-${target}-height`, `${height}%`);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
`--panel-pattern-${target}-fade-start`,
|
||||||
|
getPanelPatternFadeStart(height, activePreferences[`panelPattern${cap}Fade`]),
|
||||||
|
);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
`--panel-gradient-${target}-strength`,
|
||||||
|
String(
|
||||||
|
(clampPanelPatternPercent(
|
||||||
|
activePreferences[`panelPattern${cap}GradientOpacity`],
|
||||||
|
panelPatternTuningDefaults.gradientOpacity,
|
||||||
|
) /
|
||||||
|
100) *
|
||||||
|
0.28,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const gradientHeight = clampPanelPatternPercent(
|
||||||
|
activePreferences[`panelPattern${cap}GradientHeight`],
|
||||||
|
panelPatternTuningDefaults.gradientHeight,
|
||||||
|
);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
`--panel-gradient-${target}-height`,
|
||||||
|
`${gradientHeight}%`,
|
||||||
|
);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
`--panel-gradient-${target}-fade-start`,
|
||||||
|
getPanelPatternFadeStart(gradientHeight, activePreferences[`panelPattern${cap}GradientFade`]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncPatternTargetPanels(activePreferences) {
|
||||||
|
if (!patternTargetsPanel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const disabled = !panelFeatures.allowPanelPatternChange;
|
||||||
|
const tuningFields = ["opacity", "height", "fade", "gradientOpacity", "gradientHeight", "gradientFade"];
|
||||||
|
|
||||||
|
for (const target of panelPatternTargetIds) {
|
||||||
|
const pattern = activePreferences[getPanelPatternPreferenceKey(target, "pattern")];
|
||||||
|
patternTargetsPanel
|
||||||
|
.querySelectorAll(`[data-panel-pattern-target="${target}"][data-panel-pattern]`)
|
||||||
|
.forEach((button) => {
|
||||||
|
const isActive = button.dataset.panelPattern === pattern;
|
||||||
|
button.classList.toggle("is-active", isActive);
|
||||||
|
button.setAttribute("aria-pressed", String(isActive));
|
||||||
|
button.disabled = disabled;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const field of tuningFields) {
|
||||||
|
const key = getPanelPatternPreferenceKey(target, field);
|
||||||
|
const input = patternTargetsPanel.querySelector(
|
||||||
|
`[data-panel-pattern-tuning="${target}"][data-panel-pattern-field="${field}"]`,
|
||||||
|
);
|
||||||
|
const output = patternTargetsPanel.querySelector(
|
||||||
|
`[data-panel-pattern-value="${target}"][data-panel-pattern-field="${field}"]`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (input) {
|
||||||
|
input.value = String(activePreferences[key]);
|
||||||
|
input.disabled = disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output) {
|
||||||
|
output.textContent = `${activePreferences[key]}%`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function clampCatalogColumn(key, value) {
|
function clampCatalogColumn(key, value) {
|
||||||
const limits = getPanelLimitRange(key);
|
const limits = getPanelLimitRange(key);
|
||||||
const fallback = panelDefaults[key] ?? defaultPreferences[key];
|
const fallback = panelDefaults[key] ?? defaultPreferences[key];
|
||||||
|
|||||||
@ -31,6 +31,46 @@
|
|||||||
--catalog-list-columns: 1;
|
--catalog-list-columns: 1;
|
||||||
--catalog-compact-cards-columns: 5;
|
--catalog-compact-cards-columns: 5;
|
||||||
--catalog-compact-list-columns: 3;
|
--catalog-compact-list-columns: 3;
|
||||||
|
--pattern-color: rgba(255, 255, 255, 0.16);
|
||||||
|
--pattern-tile-hex-image: url("data:image/svg+xml,%3Csvg width='96' height='84' viewBox='0 0 96 84' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' stroke='white' stroke-opacity='.18' stroke-width='1.4'%3E%3Cpath d='M24 2 46 14v25L24 52 2 39V14L24 2Z'/%3E%3Cpath d='M72 32 94 44v25L72 82 50 69V44l22-12Z'/%3E%3C/g%3E%3C/svg%3E");
|
||||||
|
--pattern-tile-hex-size: 96px 84px;
|
||||||
|
--pattern-tile-dots-image: radial-gradient(circle at center, var(--pattern-color) 0.95px, transparent 1px);
|
||||||
|
--pattern-tile-dots-size: 18px 18px;
|
||||||
|
--pattern-tile-grid-image:
|
||||||
|
linear-gradient(var(--pattern-color) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, var(--pattern-color) 1px, transparent 1px);
|
||||||
|
--pattern-tile-grid-size: 26px 26px;
|
||||||
|
--pattern-tile-diagonal-image: repeating-linear-gradient(
|
||||||
|
-45deg,
|
||||||
|
transparent,
|
||||||
|
transparent 10px,
|
||||||
|
var(--pattern-color) 10px,
|
||||||
|
var(--pattern-color) 11px
|
||||||
|
);
|
||||||
|
--pattern-tile-diagonal-size: auto;
|
||||||
|
--pattern-tile-cross-image:
|
||||||
|
repeating-linear-gradient(
|
||||||
|
0deg,
|
||||||
|
transparent,
|
||||||
|
transparent 14px,
|
||||||
|
var(--pattern-color) 14px,
|
||||||
|
var(--pattern-color) 15px
|
||||||
|
),
|
||||||
|
repeating-linear-gradient(
|
||||||
|
90deg,
|
||||||
|
transparent,
|
||||||
|
transparent 14px,
|
||||||
|
var(--pattern-color) 14px,
|
||||||
|
var(--pattern-color) 15px
|
||||||
|
);
|
||||||
|
--pattern-tile-cross-size: auto;
|
||||||
|
--pattern-tile-mesh-image: radial-gradient(
|
||||||
|
circle at 1px 1px,
|
||||||
|
rgba(var(--accent-rgb), 0.22) 1px,
|
||||||
|
transparent 0
|
||||||
|
);
|
||||||
|
--pattern-tile-mesh-size: 20px 20px;
|
||||||
|
--settings-panel-width: 460px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Светлая тема переопределяет только токены, структура стилей остается общей. */
|
/* Светлая тема переопределяет только токены, структура стилей остается общей. */
|
||||||
@ -45,8 +85,40 @@ html[data-theme="light"] {
|
|||||||
--muted: #5f6b7a;
|
--muted: #5f6b7a;
|
||||||
--border: rgba(15, 23, 42, 0.12);
|
--border: rgba(15, 23, 42, 0.12);
|
||||||
--shadow: 0 24px 70px rgba(56, 65, 91, 0.18);
|
--shadow: 0 24px 70px rgba(56, 65, 91, 0.18);
|
||||||
|
--pattern-color: rgba(15, 23, 42, 0.13);
|
||||||
|
--pattern-tile-hex-image: url("data:image/svg+xml,%3Csvg width='96' height='84' viewBox='0 0 96 84' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' stroke='%23101827' stroke-opacity='.14' stroke-width='1.4'%3E%3Cpath d='M24 2 46 14v25L24 52 2 39V14L24 2Z'/%3E%3Cpath d='M72 32 94 44v25L72 82 50 69V44l22-12Z'/%3E%3C/g%3E%3C/svg%3E");
|
||||||
|
--pattern-tile-mesh-image: radial-gradient(
|
||||||
|
circle at 1px 1px,
|
||||||
|
rgba(var(--accent-rgb), 0.16) 1px,
|
||||||
|
transparent 0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html[data-panel-pattern-nav="hex"] { --panel-pattern-image-nav: var(--pattern-tile-hex-image); --panel-pattern-size-nav: var(--pattern-tile-hex-size); }
|
||||||
|
html[data-panel-pattern-nav="dots"] { --panel-pattern-image-nav: var(--pattern-tile-dots-image); --panel-pattern-size-nav: var(--pattern-tile-dots-size); }
|
||||||
|
html[data-panel-pattern-nav="grid"] { --panel-pattern-image-nav: var(--pattern-tile-grid-image); --panel-pattern-size-nav: var(--pattern-tile-grid-size); }
|
||||||
|
html[data-panel-pattern-nav="diagonal"] { --panel-pattern-image-nav: var(--pattern-tile-diagonal-image); --panel-pattern-size-nav: var(--pattern-tile-diagonal-size); }
|
||||||
|
html[data-panel-pattern-nav="cross"] { --panel-pattern-image-nav: var(--pattern-tile-cross-image); --panel-pattern-size-nav: var(--pattern-tile-cross-size); }
|
||||||
|
html[data-panel-pattern-nav="mesh"] { --panel-pattern-image-nav: var(--pattern-tile-mesh-image); --panel-pattern-size-nav: var(--pattern-tile-mesh-size); }
|
||||||
|
html[data-panel-pattern-section="hex"] { --panel-pattern-image-section: var(--pattern-tile-hex-image); --panel-pattern-size-section: var(--pattern-tile-hex-size); }
|
||||||
|
html[data-panel-pattern-section="dots"] { --panel-pattern-image-section: var(--pattern-tile-dots-image); --panel-pattern-size-section: var(--pattern-tile-dots-size); }
|
||||||
|
html[data-panel-pattern-section="grid"] { --panel-pattern-image-section: var(--pattern-tile-grid-image); --panel-pattern-size-section: var(--pattern-tile-grid-size); }
|
||||||
|
html[data-panel-pattern-section="diagonal"] { --panel-pattern-image-section: var(--pattern-tile-diagonal-image); --panel-pattern-size-section: var(--pattern-tile-diagonal-size); }
|
||||||
|
html[data-panel-pattern-section="cross"] { --panel-pattern-image-section: var(--pattern-tile-cross-image); --panel-pattern-size-section: var(--pattern-tile-cross-size); }
|
||||||
|
html[data-panel-pattern-section="mesh"] { --panel-pattern-image-section: var(--pattern-tile-mesh-image); --panel-pattern-size-section: var(--pattern-tile-mesh-size); }
|
||||||
|
html[data-panel-pattern-group="hex"] { --panel-pattern-image-group: var(--pattern-tile-hex-image); --panel-pattern-size-group: var(--pattern-tile-hex-size); }
|
||||||
|
html[data-panel-pattern-group="dots"] { --panel-pattern-image-group: var(--pattern-tile-dots-image); --panel-pattern-size-group: var(--pattern-tile-dots-size); }
|
||||||
|
html[data-panel-pattern-group="grid"] { --panel-pattern-image-group: var(--pattern-tile-grid-image); --panel-pattern-size-group: var(--pattern-tile-grid-size); }
|
||||||
|
html[data-panel-pattern-group="diagonal"] { --panel-pattern-image-group: var(--pattern-tile-diagonal-image); --panel-pattern-size-group: var(--pattern-tile-diagonal-size); }
|
||||||
|
html[data-panel-pattern-group="cross"] { --panel-pattern-image-group: var(--pattern-tile-cross-image); --panel-pattern-size-group: var(--pattern-tile-cross-size); }
|
||||||
|
html[data-panel-pattern-group="mesh"] { --panel-pattern-image-group: var(--pattern-tile-mesh-image); --panel-pattern-size-group: var(--pattern-tile-mesh-size); }
|
||||||
|
html[data-panel-pattern-item="hex"] { --panel-pattern-image-item: var(--pattern-tile-hex-image); --panel-pattern-size-item: var(--pattern-tile-hex-size); }
|
||||||
|
html[data-panel-pattern-item="dots"] { --panel-pattern-image-item: var(--pattern-tile-dots-image); --panel-pattern-size-item: var(--pattern-tile-dots-size); }
|
||||||
|
html[data-panel-pattern-item="grid"] { --panel-pattern-image-item: var(--pattern-tile-grid-image); --panel-pattern-size-item: var(--pattern-tile-grid-size); }
|
||||||
|
html[data-panel-pattern-item="diagonal"] { --panel-pattern-image-item: var(--pattern-tile-diagonal-image); --panel-pattern-size-item: var(--pattern-tile-diagonal-size); }
|
||||||
|
html[data-panel-pattern-item="cross"] { --panel-pattern-image-item: var(--pattern-tile-cross-image); --panel-pattern-size-item: var(--pattern-tile-cross-size); }
|
||||||
|
html[data-panel-pattern-item="mesh"] { --panel-pattern-image-item: var(--pattern-tile-mesh-image); --panel-pattern-size-item: var(--pattern-tile-mesh-size); }
|
||||||
|
|
||||||
/* Наборы акцентов. --accent-rgb нужен для прозрачных градиентов через rgba(). */
|
/* Наборы акцентов. --accent-rgb нужен для прозрачных градиентов через rgba(). */
|
||||||
html[data-accent="cyan"] {
|
html[data-accent="cyan"] {
|
||||||
--accent: #06b6d4;
|
--accent: #06b6d4;
|
||||||
@ -324,6 +396,8 @@ body.is-resizing-top-bar {
|
|||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
box-shadow: var(--shadow);
|
box-shadow: var(--shadow);
|
||||||
backdrop-filter: blur(22px);
|
backdrop-filter: blur(22px);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-content {
|
.hero-content {
|
||||||
@ -335,7 +409,6 @@ body.is-resizing-top-bar {
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding: clamp(16px, 2.6vw, 24px);
|
padding: clamp(16px, 2.6vw, 24px);
|
||||||
border-radius: 22px;
|
border-radius: 22px;
|
||||||
position: relative;
|
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,21 +417,117 @@ body.is-resizing-top-bar {
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Внутренний фон sidebar: градиент + hexagon pattern. */
|
/* Акцентный градиент под узором — отдельно для каждого типа блоков. */
|
||||||
.hero-content::before {
|
html:not([data-panel-pattern-nav="none"]) .hero-content::before {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
border-radius: inherit;
|
border-radius: inherit;
|
||||||
background:
|
background: linear-gradient(120deg, rgba(var(--accent-rgb), 1), transparent 38%);
|
||||||
linear-gradient(120deg, rgba(var(--accent-rgb), 0.25), transparent 34%),
|
opacity: var(--panel-gradient-nav-strength);
|
||||||
url("data:image/svg+xml,%3Csvg width='96' height='84' viewBox='0 0 96 84' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' stroke='white' stroke-opacity='.10' stroke-width='1.4'%3E%3Cpath d='M24 2 46 14v25L24 52 2 39V14L24 2Z'/%3E%3Cpath d='M72 32 94 44v25L72 82 50 69V44l22-12Z'/%3E%3C/g%3E%3C/svg%3E");
|
mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-gradient-nav-fade-start), transparent var(--panel-gradient-nav-height));
|
||||||
mask-image: linear-gradient(to bottom, black, transparent 88%);
|
-webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-gradient-nav-fade-start), transparent var(--panel-gradient-nav-height));
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html:not([data-panel-pattern-section="none"]) .catalog-section::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
background: linear-gradient(120deg, rgba(var(--accent-rgb), 1), transparent 38%);
|
||||||
|
opacity: var(--panel-gradient-section-strength);
|
||||||
|
mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-gradient-section-fade-start), transparent var(--panel-gradient-section-height));
|
||||||
|
-webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-gradient-section-fade-start), transparent var(--panel-gradient-section-height));
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html:not([data-panel-pattern-group="none"]) .catalog-group::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
background: linear-gradient(120deg, rgba(var(--accent-rgb), 1), transparent 38%);
|
||||||
|
opacity: var(--panel-gradient-group-strength);
|
||||||
|
mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-gradient-group-fade-start), transparent var(--panel-gradient-group-height));
|
||||||
|
-webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-gradient-group-fade-start), transparent var(--panel-gradient-group-height));
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html:not([data-panel-pattern-nav="none"]) .hero-content::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
opacity: var(--panel-pattern-nav-opacity);
|
||||||
|
background-image: var(--panel-pattern-image-nav);
|
||||||
|
background-size: var(--panel-pattern-size-nav);
|
||||||
|
background-repeat: repeat;
|
||||||
|
mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-pattern-nav-fade-start), transparent var(--panel-pattern-nav-height));
|
||||||
|
-webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-pattern-nav-fade-start), transparent var(--panel-pattern-nav-height));
|
||||||
|
}
|
||||||
|
|
||||||
|
html:not([data-panel-pattern-section="none"]) .catalog-section::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
opacity: var(--panel-pattern-section-opacity);
|
||||||
|
background-image: var(--panel-pattern-image-section);
|
||||||
|
background-size: var(--panel-pattern-size-section);
|
||||||
|
background-repeat: repeat;
|
||||||
|
mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-pattern-section-fade-start), transparent var(--panel-pattern-section-height));
|
||||||
|
-webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-pattern-section-fade-start), transparent var(--panel-pattern-section-height));
|
||||||
|
}
|
||||||
|
|
||||||
|
html:not([data-panel-pattern-group="none"]) .catalog-group::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
opacity: var(--panel-pattern-group-opacity);
|
||||||
|
background-image: var(--panel-pattern-image-group);
|
||||||
|
background-size: var(--panel-pattern-size-group);
|
||||||
|
background-repeat: repeat;
|
||||||
|
mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-pattern-group-fade-start), transparent var(--panel-pattern-group-height));
|
||||||
|
-webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-pattern-group-fade-start), transparent var(--panel-pattern-group-height));
|
||||||
|
}
|
||||||
|
|
||||||
|
html:not([data-panel-pattern-item="none"]) .nav-card::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
opacity: var(--panel-pattern-item-opacity);
|
||||||
|
background-image: var(--panel-pattern-image-item);
|
||||||
|
background-size: var(--panel-pattern-size-item);
|
||||||
|
background-repeat: repeat;
|
||||||
|
mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-pattern-item-fade-start), transparent var(--panel-pattern-item-height));
|
||||||
|
-webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-pattern-item-fade-start), transparent var(--panel-pattern-item-height));
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog-section > summary,
|
||||||
|
.catalog-section > .section-groups,
|
||||||
|
.catalog-group > summary,
|
||||||
|
.catalog-group > .items-grid {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-content > * {
|
.hero-content > * {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Общий стиль маленьких uppercase-меток и номеров. */
|
/* Общий стиль маленьких uppercase-меток и номеров. */
|
||||||
@ -414,7 +583,7 @@ html[data-show-tree-tags="false"][data-show-tree-type="false"] .tree-file-meta {
|
|||||||
z-index: 1001;
|
z-index: 1001;
|
||||||
top: 24px;
|
top: 24px;
|
||||||
right: 24px;
|
right: 24px;
|
||||||
width: min(460px, calc(100% - 48px));
|
width: min(var(--settings-panel-width), calc(100% - 48px));
|
||||||
max-height: calc(100vh - 48px);
|
max-height: calc(100vh - 48px);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -512,6 +681,27 @@ html[data-show-tree-tags="false"][data-show-tree-type="false"] .tree-file-meta {
|
|||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.settings-width-row {
|
||||||
|
grid-template-columns: minmax(0, 1fr) auto;
|
||||||
|
grid-template-rows: auto auto;
|
||||||
|
gap: 6px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-width-row span {
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-width-row output {
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-width-row input[type="range"] {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
grid-row: 2;
|
||||||
|
}
|
||||||
|
|
||||||
.settings-section {
|
.settings-section {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
@ -901,6 +1091,166 @@ html[data-theme="light"] .accent-swatch-custom {
|
|||||||
transform: scale(1.05);
|
transform: scale(1.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pattern-group {
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-targets-panel {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-target-panel .settings-section-body {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatches {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 8px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch {
|
||||||
|
min-height: 54px;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 14px;
|
||||||
|
background: var(--surface);
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
opacity: 0.95;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch[data-panel-pattern="none"]::before {
|
||||||
|
background: linear-gradient(135deg, rgba(var(--accent-rgb), 0.12), transparent 70%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch[data-panel-pattern="hex"]::before {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg width='96' height='84' viewBox='0 0 96 84' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' stroke='white' stroke-opacity='.18' stroke-width='1.4'%3E%3Cpath d='M24 2 46 14v25L24 52 2 39V14L24 2Z'/%3E%3Cpath d='M72 32 94 44v25L72 82 50 69V44l22-12Z'/%3E%3C/g%3E%3C/svg%3E");
|
||||||
|
background-size: 48px 42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme="light"] .pattern-swatch[data-panel-pattern="hex"]::before {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg width='96' height='84' viewBox='0 0 96 84' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' stroke='%23101827' stroke-opacity='.14' stroke-width='1.4'%3E%3Cpath d='M24 2 46 14v25L24 52 2 39V14L24 2Z'/%3E%3Cpath d='M72 32 94 44v25L72 82 50 69V44l22-12Z'/%3E%3C/g%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch[data-panel-pattern="dots"]::before {
|
||||||
|
background-image: radial-gradient(circle at center, var(--pattern-color) 0.95px, transparent 1px);
|
||||||
|
background-size: 12px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch[data-panel-pattern="grid"]::before {
|
||||||
|
background-image:
|
||||||
|
linear-gradient(var(--pattern-color) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, var(--pattern-color) 1px, transparent 1px);
|
||||||
|
background-size: 16px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch[data-panel-pattern="diagonal"]::before {
|
||||||
|
background-image: repeating-linear-gradient(
|
||||||
|
-45deg,
|
||||||
|
transparent,
|
||||||
|
transparent 7px,
|
||||||
|
var(--pattern-color) 7px,
|
||||||
|
var(--pattern-color) 8px
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch[data-panel-pattern="cross"]::before {
|
||||||
|
background-image:
|
||||||
|
repeating-linear-gradient(
|
||||||
|
0deg,
|
||||||
|
transparent,
|
||||||
|
transparent 9px,
|
||||||
|
var(--pattern-color) 9px,
|
||||||
|
var(--pattern-color) 10px
|
||||||
|
),
|
||||||
|
repeating-linear-gradient(
|
||||||
|
90deg,
|
||||||
|
transparent,
|
||||||
|
transparent 9px,
|
||||||
|
var(--pattern-color) 9px,
|
||||||
|
var(--pattern-color) 10px
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch[data-panel-pattern="mesh"]::before {
|
||||||
|
background-image: radial-gradient(
|
||||||
|
circle at 1px 1px,
|
||||||
|
rgba(var(--accent-rgb), 0.24) 1px,
|
||||||
|
transparent 0
|
||||||
|
);
|
||||||
|
background-size: 12px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch-label {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
display: grid;
|
||||||
|
place-items: end start;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 6px 8px;
|
||||||
|
background: linear-gradient(to top, rgba(0, 0, 0, 0.28), transparent 58%);
|
||||||
|
color: #f8fafc;
|
||||||
|
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme="light"] .pattern-swatch-label {
|
||||||
|
background: linear-gradient(to top, rgba(255, 255, 255, 0.82), transparent 58%);
|
||||||
|
color: #101827;
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch.is-active {
|
||||||
|
border-color: rgba(var(--accent-rgb), 0.72);
|
||||||
|
box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-tuning {
|
||||||
|
display: grid;
|
||||||
|
gap: 12px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-tuning .accent-custom-row {
|
||||||
|
grid-template-columns: minmax(0, 1fr) auto;
|
||||||
|
grid-template-rows: auto auto;
|
||||||
|
gap: 6px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-tuning .accent-custom-row span {
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-tuning .accent-custom-row output {
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-tuning .accent-custom-row input[type="range"] {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
grid-row: 2;
|
||||||
|
}
|
||||||
|
|
||||||
/* Панель настройки своего градиента появляется при data-accent="custom". */
|
/* Панель настройки своего градиента появляется при data-accent="custom". */
|
||||||
.accent-custom-panel {
|
.accent-custom-panel {
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -1329,6 +1679,7 @@ html:not([data-tree-columns="1"]) .tree-node-icon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.catalog-group {
|
.catalog-group {
|
||||||
|
position: relative;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: 18px;
|
border-radius: 18px;
|
||||||
background: rgba(255, 255, 255, 0.035);
|
background: rgba(255, 255, 255, 0.035);
|
||||||
@ -1427,6 +1778,7 @@ html:not([data-tree-columns="1"]) .tree-node-icon {
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 180ms ease;
|
transition: opacity 180ms ease;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hover задается классом .is-hovered из JS, чтобы убрать скачки на границах. */
|
/* Hover задается классом .is-hovered из JS, чтобы убрать скачки на границах. */
|
||||||
@ -1445,6 +1797,8 @@ html:not([data-tree-columns="1"]) .tree-node-icon {
|
|||||||
|
|
||||||
/* Иконка сервиса берется из serviceMeta. */
|
/* Иконка сервиса берется из serviceMeta. */
|
||||||
.nav-card img {
|
.nav-card img {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
@ -1453,6 +1807,7 @@ html:not([data-tree-columns="1"]) .tree-node-icon {
|
|||||||
|
|
||||||
.card-content {
|
.card-content {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
}
|
}
|
||||||
@ -1493,6 +1848,7 @@ html:not([data-tree-columns="1"]) .tree-node-icon {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
right: 16px;
|
right: 16px;
|
||||||
bottom: 14px;
|
bottom: 14px;
|
||||||
|
z-index: 1;
|
||||||
width: 36px;
|
width: 36px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -1515,6 +1871,7 @@ html:not([data-tree-columns="1"]) .tree-node-icon {
|
|||||||
.shine {
|
.shine {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
|
z-index: 2;
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
110deg,
|
110deg,
|
||||||
transparent 0%,
|
transparent 0%,
|
||||||
|
|||||||
113
index.html
113
index.html
@ -127,6 +127,11 @@
|
|||||||
</span>
|
</span>
|
||||||
<input type="checkbox" data-show-resize-handles checked />
|
<input type="checkbox" data-show-resize-handles checked />
|
||||||
</label>
|
</label>
|
||||||
|
<label class="accent-custom-row settings-width-row">
|
||||||
|
<span>Ширина настроек</span>
|
||||||
|
<input type="range" data-settings-panel-width />
|
||||||
|
<output data-settings-panel-width-value>460px</output>
|
||||||
|
</label>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<details class="settings-section settings-section-collapsible" data-settings-section="dimensions">
|
<details class="settings-section settings-section-collapsible" data-settings-section="dimensions">
|
||||||
@ -369,6 +374,114 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="pattern-targets-panel" data-pattern-targets-panel data-feature="allowPanelPatternChange">
|
||||||
|
<p class="settings-section-hint">Узор и градиент настраиваются отдельно для каждого типа блоков.</p>
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="nav">
|
||||||
|
<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">Боковое меню и дерево</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="none" aria-pressed="false"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="nav" data-panel-pattern="hex" aria-pressed="true"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="nav" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="nav" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="nav" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="nav" data-panel-pattern-field="height" /><output data-panel-pattern-value="nav" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="nav" data-panel-pattern-field="fade" /><output data-panel-pattern-value="nav" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: прозрачность</span><input type="range" min="0" max="100" step="1" value="80" data-panel-pattern-tuning="nav" data-panel-pattern-field="gradientOpacity" /><output data-panel-pattern-value="nav" data-panel-pattern-field="gradientOpacity">80%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: высота</span><input type="range" min="0" max="100" step="1" value="40" data-panel-pattern-tuning="nav" data-panel-pattern-field="gradientHeight" /><output data-panel-pattern-value="nav" data-panel-pattern-field="gradientHeight">40%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: переход</span><input type="range" min="0" max="100" step="1" value="8" data-panel-pattern-tuning="nav" data-panel-pattern-field="gradientFade" /><output data-panel-pattern-value="nav" data-panel-pattern-field="gradientFade">8%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="section">
|
||||||
|
<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">Карточки верхнего уровня каталога</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="none" aria-pressed="false"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="section" data-panel-pattern="hex" aria-pressed="true"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="section" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="section" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="section" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="section" data-panel-pattern-field="height" /><output data-panel-pattern-value="section" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="section" data-panel-pattern-field="fade" /><output data-panel-pattern-value="section" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: прозрачность</span><input type="range" min="0" max="100" step="1" value="80" data-panel-pattern-tuning="section" data-panel-pattern-field="gradientOpacity" /><output data-panel-pattern-value="section" data-panel-pattern-field="gradientOpacity">80%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: высота</span><input type="range" min="0" max="100" step="1" value="40" data-panel-pattern-tuning="section" data-panel-pattern-field="gradientHeight" /><output data-panel-pattern-value="section" data-panel-pattern-field="gradientHeight">40%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: переход</span><input type="range" min="0" max="100" step="1" value="8" data-panel-pattern-tuning="section" data-panel-pattern-field="gradientFade" /><output data-panel-pattern-value="section" data-panel-pattern-field="gradientFade">8%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="group">
|
||||||
|
<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">Группы внутри раздела</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="group" data-panel-pattern="none" aria-pressed="true"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="hex" aria-pressed="false"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="group" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="group" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="group" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="group" data-panel-pattern-field="height" /><output data-panel-pattern-value="group" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="group" data-panel-pattern-field="fade" /><output data-panel-pattern-value="group" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: прозрачность</span><input type="range" min="0" max="100" step="1" value="80" data-panel-pattern-tuning="group" data-panel-pattern-field="gradientOpacity" /><output data-panel-pattern-value="group" data-panel-pattern-field="gradientOpacity">80%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: высота</span><input type="range" min="0" max="100" step="1" value="40" data-panel-pattern-tuning="group" data-panel-pattern-field="gradientHeight" /><output data-panel-pattern-value="group" data-panel-pattern-field="gradientHeight">40%</output></label>
|
||||||
|
<label class="accent-custom-row pattern-gradient-tuning"><span>Градиент: переход</span><input type="range" min="0" max="100" step="1" value="8" data-panel-pattern-tuning="group" data-panel-pattern-field="gradientFade" /><output data-panel-pattern-value="group" data-panel-pattern-field="gradientFade">8%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details class="settings-section-collapsible pattern-target-panel" data-pattern-target="item">
|
||||||
|
<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">Карточки сервисов — только узор, без акцентного градиента</p>
|
||||||
|
<div class="pattern-swatches">
|
||||||
|
<button class="pattern-swatch is-active" type="button" data-panel-pattern-target="item" data-panel-pattern="none" aria-pressed="true"><span class="pattern-swatch-label">Нет</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="hex" aria-pressed="false"><span class="pattern-swatch-label">Соты</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="dots" aria-pressed="false"><span class="pattern-swatch-label">Точки</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="grid" aria-pressed="false"><span class="pattern-swatch-label">Сетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="diagonal" aria-pressed="false"><span class="pattern-swatch-label">Диаг.</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="cross" aria-pressed="false"><span class="pattern-swatch-label">Клетка</span></button>
|
||||||
|
<button class="pattern-swatch" type="button" data-panel-pattern-target="item" data-panel-pattern="mesh" aria-pressed="false"><span class="pattern-swatch-label">Mesh</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="pattern-tuning">
|
||||||
|
<label class="accent-custom-row"><span>Узор: прозрачность</span><input type="range" min="0" max="100" step="1" value="70" data-panel-pattern-tuning="item" data-panel-pattern-field="opacity" /><output data-panel-pattern-value="item" data-panel-pattern-field="opacity">70%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: высота</span><input type="range" min="0" max="100" step="1" value="45" data-panel-pattern-tuning="item" data-panel-pattern-field="height" /><output data-panel-pattern-value="item" data-panel-pattern-field="height">45%</output></label>
|
||||||
|
<label class="accent-custom-row"><span>Узор: переход</span><input type="range" min="0" max="100" step="1" value="10" data-panel-pattern-tuning="item" data-panel-pattern-field="fade" /><output data-panel-pattern-value="item" data-panel-pattern-field="fade">10%</output></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Настройки пользовательского linear-gradient акцента. -->
|
<!-- Настройки пользовательского linear-gradient акцента. -->
|
||||||
<div class="accent-custom-panel" data-accent-custom-panel data-feature="allowAccentChange" hidden>
|
<div class="accent-custom-panel" data-accent-custom-panel data-feature="allowAccentChange" hidden>
|
||||||
<p class="accent-custom-title">Свой градиент</p>
|
<p class="accent-custom-title">Свой градиент</p>
|
||||||
|
|||||||
321
script.js
321
script.js
@ -65,6 +65,44 @@ const defaultServiceMeta = {
|
|||||||
|
|
||||||
let serviceMeta = { ...defaultServiceMeta };
|
let serviceMeta = { ...defaultServiceMeta };
|
||||||
|
|
||||||
|
const availablePanelPatterns = ["none", "hex", "dots", "grid", "diagonal", "cross", "mesh"];
|
||||||
|
const panelPatternTargetIds = ["nav", "section", "group", "item"];
|
||||||
|
const panelPatternTuningDefaults = {
|
||||||
|
opacity: 70,
|
||||||
|
height: 45,
|
||||||
|
fade: 10,
|
||||||
|
gradientOpacity: 80,
|
||||||
|
gradientHeight: 40,
|
||||||
|
gradientFade: 8,
|
||||||
|
};
|
||||||
|
const panelPatternTargetMeta = {
|
||||||
|
nav: { defaultPattern: "hex" },
|
||||||
|
section: { defaultPattern: "hex" },
|
||||||
|
group: { defaultPattern: "none" },
|
||||||
|
item: { defaultPattern: "none" },
|
||||||
|
};
|
||||||
|
|
||||||
|
function capitalizePanelPatternTarget(target) {
|
||||||
|
return target.charAt(0).toUpperCase() + target.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildDefaultPanelPatternPreferences() {
|
||||||
|
const prefs = {};
|
||||||
|
|
||||||
|
for (const target of panelPatternTargetIds) {
|
||||||
|
const cap = capitalizePanelPatternTarget(target);
|
||||||
|
prefs[`panelPattern${cap}`] = panelPatternTargetMeta[target].defaultPattern;
|
||||||
|
prefs[`panelPattern${cap}Opacity`] = panelPatternTuningDefaults.opacity;
|
||||||
|
prefs[`panelPattern${cap}Height`] = panelPatternTuningDefaults.height;
|
||||||
|
prefs[`panelPattern${cap}Fade`] = panelPatternTuningDefaults.fade;
|
||||||
|
prefs[`panelPattern${cap}GradientOpacity`] = panelPatternTuningDefaults.gradientOpacity;
|
||||||
|
prefs[`panelPattern${cap}GradientHeight`] = panelPatternTuningDefaults.gradientHeight;
|
||||||
|
prefs[`panelPattern${cap}GradientFade`] = panelPatternTuningDefaults.gradientFade;
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefs;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Default UI preferences
|
// Default UI preferences
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -76,6 +114,7 @@ const defaultPreferences = {
|
|||||||
customAccentFrom: "#8b5cf6",
|
customAccentFrom: "#8b5cf6",
|
||||||
customAccentTo: "#22d3ee",
|
customAccentTo: "#22d3ee",
|
||||||
customAccentAngle: 135,
|
customAccentAngle: 135,
|
||||||
|
...buildDefaultPanelPatternPreferences(),
|
||||||
navLayout: "sidebar",
|
navLayout: "sidebar",
|
||||||
showTree: true,
|
showTree: true,
|
||||||
showResizeHandles: true,
|
showResizeHandles: true,
|
||||||
@ -100,6 +139,7 @@ const defaultPreferences = {
|
|||||||
catalogCompactCardsColumns: 5,
|
catalogCompactCardsColumns: 5,
|
||||||
catalogCompactListColumns: 3,
|
catalogCompactListColumns: 3,
|
||||||
searchPlaceholder: "Grafana, S3, журнал, сервер...",
|
searchPlaceholder: "Grafana, S3, журнал, сервер...",
|
||||||
|
settingsPanelWidth: 460,
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultPanelFeatures = {
|
const defaultPanelFeatures = {
|
||||||
@ -114,6 +154,7 @@ const defaultPanelFeatures = {
|
|||||||
allowLayoutLimitsChange: true,
|
allowLayoutLimitsChange: true,
|
||||||
allowThemeChange: true,
|
allowThemeChange: true,
|
||||||
allowAccentChange: true,
|
allowAccentChange: true,
|
||||||
|
allowPanelPatternChange: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultPanelLimits = {
|
const defaultPanelLimits = {
|
||||||
@ -129,6 +170,7 @@ const defaultPanelLimits = {
|
|||||||
catalogListColumns: { min: 1, max: 4 },
|
catalogListColumns: { min: 1, max: 4 },
|
||||||
catalogCompactCardsColumns: { min: 2, max: 8 },
|
catalogCompactCardsColumns: { min: 2, max: 8 },
|
||||||
catalogCompactListColumns: { min: 1, max: 6 },
|
catalogCompactListColumns: { min: 1, max: 6 },
|
||||||
|
settingsPanelWidth: { min: 320, max: 720 },
|
||||||
};
|
};
|
||||||
|
|
||||||
const layoutLimitKeys = [
|
const layoutLimitKeys = [
|
||||||
@ -149,7 +191,7 @@ const catalogColumnKeys = [
|
|||||||
"catalogCompactListColumns",
|
"catalogCompactListColumns",
|
||||||
];
|
];
|
||||||
|
|
||||||
const panelLimitKeys = [...layoutLimitKeys, ...catalogColumnKeys];
|
const panelLimitKeys = [...layoutLimitKeys, ...catalogColumnKeys, "settingsPanelWidth"];
|
||||||
|
|
||||||
const availableNavLayouts = ["sidebar", "top"];
|
const availableNavLayouts = ["sidebar", "top"];
|
||||||
const availableTreeMetaLayouts = ["inline", "stacked"];
|
const availableTreeMetaLayouts = ["inline", "stacked"];
|
||||||
@ -186,6 +228,7 @@ const themeButtons = document.querySelectorAll("[data-theme]");
|
|||||||
const navLayoutButtons = document.querySelectorAll("[data-nav-layout]");
|
const navLayoutButtons = document.querySelectorAll("[data-nav-layout]");
|
||||||
const viewButtons = document.querySelectorAll("[data-view]");
|
const viewButtons = document.querySelectorAll("[data-view]");
|
||||||
const accentButtons = document.querySelectorAll("[data-accent]");
|
const accentButtons = document.querySelectorAll("[data-accent]");
|
||||||
|
const patternTargetsPanel = document.querySelector("[data-pattern-targets-panel]");
|
||||||
const accentCustomPanel = document.querySelector("[data-accent-custom-panel]");
|
const accentCustomPanel = document.querySelector("[data-accent-custom-panel]");
|
||||||
const customAccentFromInput = document.querySelector("[data-custom-accent-from]");
|
const customAccentFromInput = document.querySelector("[data-custom-accent-from]");
|
||||||
const customAccentToInput = document.querySelector("[data-custom-accent-to]");
|
const customAccentToInput = document.querySelector("[data-custom-accent-to]");
|
||||||
@ -201,6 +244,8 @@ const treeColumnsInput = document.querySelector("[data-tree-columns]");
|
|||||||
const treeColumnsValue = document.querySelector("[data-tree-columns-value]");
|
const treeColumnsValue = document.querySelector("[data-tree-columns-value]");
|
||||||
const treeMetaLayoutButtons = document.querySelectorAll("[data-tree-meta-layout]");
|
const treeMetaLayoutButtons = document.querySelectorAll("[data-tree-meta-layout]");
|
||||||
const autoCollapseSearchInput = document.querySelector("[data-auto-collapse-search]");
|
const autoCollapseSearchInput = document.querySelector("[data-auto-collapse-search]");
|
||||||
|
const settingsPanelWidthInput = document.querySelector("[data-settings-panel-width]");
|
||||||
|
const settingsPanelWidthValue = document.querySelector("[data-settings-panel-width-value]");
|
||||||
const layoutLimitInputs = document.querySelectorAll("[data-layout-limit]");
|
const layoutLimitInputs = document.querySelectorAll("[data-layout-limit]");
|
||||||
const catalogColumnInputs = document.querySelectorAll("[data-catalog-columns]");
|
const catalogColumnInputs = document.querySelectorAll("[data-catalog-columns]");
|
||||||
const settingsSections = document.querySelectorAll("[data-settings-section]");
|
const settingsSections = document.querySelectorAll("[data-settings-section]");
|
||||||
@ -388,6 +433,35 @@ accentButtons.forEach((button) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
patternTargetsPanel?.addEventListener("click", (event) => {
|
||||||
|
const button = event.target.closest("[data-panel-pattern-target][data-panel-pattern]");
|
||||||
|
|
||||||
|
if (!button || !panelFeatures.allowPanelPatternChange) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const target = button.dataset.panelPatternTarget;
|
||||||
|
preferences[getPanelPatternPreferenceKey(target, "pattern")] = button.dataset.panelPattern;
|
||||||
|
applyPreferences(preferences);
|
||||||
|
savePreferences(preferences);
|
||||||
|
});
|
||||||
|
|
||||||
|
patternTargetsPanel?.addEventListener("input", (event) => {
|
||||||
|
const input = event.target.closest("[data-panel-pattern-tuning]");
|
||||||
|
|
||||||
|
if (!input || !panelFeatures.allowPanelPatternChange) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const target = input.dataset.panelPatternTuning;
|
||||||
|
const field = input.dataset.panelPatternField;
|
||||||
|
const key = getPanelPatternPreferenceKey(target, field);
|
||||||
|
const fallback = defaultPreferences[key] ?? panelPatternTuningDefaults[field] ?? 50;
|
||||||
|
preferences[key] = clampPanelPatternPercent(input.value, fallback);
|
||||||
|
applyPreferences(preferences);
|
||||||
|
savePreferences(preferences);
|
||||||
|
});
|
||||||
|
|
||||||
// Изменение параметров своего градиента сразу переключает accent на custom.
|
// Изменение параметров своего градиента сразу переключает accent на custom.
|
||||||
function handleCustomAccentChange() {
|
function handleCustomAccentChange() {
|
||||||
if (!panelFeatures.allowAccentChange) {
|
if (!panelFeatures.allowAccentChange) {
|
||||||
@ -459,6 +533,17 @@ if (treeColumnsInput) {
|
|||||||
treeColumnsInput.addEventListener("input", handleTreeColumnsChange);
|
treeColumnsInput.addEventListener("input", handleTreeColumnsChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSettingsPanelWidthChange() {
|
||||||
|
preferences.settingsPanelWidth = clampLayoutPreference(
|
||||||
|
"settingsPanelWidth",
|
||||||
|
settingsPanelWidthInput?.value,
|
||||||
|
);
|
||||||
|
applyPreferences(preferences);
|
||||||
|
savePreferences(preferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
settingsPanelWidthInput?.addEventListener("input", handleSettingsPanelWidthChange);
|
||||||
|
|
||||||
treeMetaLayoutButtons.forEach((button) => {
|
treeMetaLayoutButtons.forEach((button) => {
|
||||||
button.addEventListener("click", () => {
|
button.addEventListener("click", () => {
|
||||||
if (!panelFeatures.allowTreeOptions || !isTreeVisible(preferences)) {
|
if (!panelFeatures.allowTreeOptions || !isTreeVisible(preferences)) {
|
||||||
@ -625,6 +710,9 @@ function normalizePreferences(raw) {
|
|||||||
next.accent = defaultPreferences.accent;
|
next.accent = defaultPreferences.accent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
migrateLegacyPanelPatternPreferences(next);
|
||||||
|
normalizePanelPatternPreferences(next);
|
||||||
|
|
||||||
if (!availableNavLayouts.includes(next.navLayout)) {
|
if (!availableNavLayouts.includes(next.navLayout)) {
|
||||||
next.navLayout = defaultPreferences.navLayout;
|
next.navLayout = defaultPreferences.navLayout;
|
||||||
}
|
}
|
||||||
@ -659,6 +747,7 @@ function normalizePreferences(raw) {
|
|||||||
getTopBarMinHeight(next),
|
getTopBarMinHeight(next),
|
||||||
getTopBarMaxHeight(next),
|
getTopBarMaxHeight(next),
|
||||||
);
|
);
|
||||||
|
next.settingsPanelWidth = clampLayoutPreference("settingsPanelWidth", next.settingsPanelWidth);
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
@ -724,6 +813,19 @@ function enforceFeatureLocks(rawPreferences) {
|
|||||||
next.customAccentAngle = panelDefaults.customAccentAngle;
|
next.customAccentAngle = panelDefaults.customAccentAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!panelFeatures.allowPanelPatternChange) {
|
||||||
|
for (const target of panelPatternTargetIds) {
|
||||||
|
const cap = capitalizePanelPatternTarget(target);
|
||||||
|
next[`panelPattern${cap}`] = panelDefaults[`panelPattern${cap}`];
|
||||||
|
next[`panelPattern${cap}Opacity`] = panelDefaults[`panelPattern${cap}Opacity`];
|
||||||
|
next[`panelPattern${cap}Height`] = panelDefaults[`panelPattern${cap}Height`];
|
||||||
|
next[`panelPattern${cap}Fade`] = panelDefaults[`panelPattern${cap}Fade`];
|
||||||
|
next[`panelPattern${cap}GradientOpacity`] = panelDefaults[`panelPattern${cap}GradientOpacity`];
|
||||||
|
next[`panelPattern${cap}GradientHeight`] = panelDefaults[`panelPattern${cap}GradientHeight`];
|
||||||
|
next[`panelPattern${cap}GradientFade`] = panelDefaults[`panelPattern${cap}GradientFade`];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!panelFeatures.allowShowNumbers) {
|
if (!panelFeatures.allowShowNumbers) {
|
||||||
next.showNumbers = panelDefaults.showNumbers;
|
next.showNumbers = panelDefaults.showNumbers;
|
||||||
}
|
}
|
||||||
@ -1370,6 +1472,7 @@ function applyPreferences(nextPreferences) {
|
|||||||
|
|
||||||
document.documentElement.dataset.theme = activePreferences.theme;
|
document.documentElement.dataset.theme = activePreferences.theme;
|
||||||
document.documentElement.dataset.accent = activePreferences.accent;
|
document.documentElement.dataset.accent = activePreferences.accent;
|
||||||
|
applyPanelPatternPreferences(activePreferences);
|
||||||
document.documentElement.dataset.navLayout =
|
document.documentElement.dataset.navLayout =
|
||||||
activePreferences.navLayout === "top" ? "top" : "sidebar";
|
activePreferences.navLayout === "top" ? "top" : "sidebar";
|
||||||
document.documentElement.dataset.showTree = String(isTreeVisible(activePreferences));
|
document.documentElement.dataset.showTree = String(isTreeVisible(activePreferences));
|
||||||
@ -1391,6 +1494,10 @@ function applyPreferences(nextPreferences) {
|
|||||||
getTopBarMaxHeight(activePreferences),
|
getTopBarMaxHeight(activePreferences),
|
||||||
)}px`,
|
)}px`,
|
||||||
);
|
);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
"--settings-panel-width",
|
||||||
|
`${clampLayoutPreference("settingsPanelWidth", activePreferences.settingsPanelWidth)}px`,
|
||||||
|
);
|
||||||
const treeColumns = getTreeColumns(activePreferences);
|
const treeColumns = getTreeColumns(activePreferences);
|
||||||
const sidebarMaxWidth = getSidebarMaxWidth(activePreferences);
|
const sidebarMaxWidth = getSidebarMaxWidth(activePreferences);
|
||||||
|
|
||||||
@ -1461,9 +1568,11 @@ function applyPreferences(nextPreferences) {
|
|||||||
setActiveButton(navLayoutButtons, "navLayout", activePreferences.navLayout);
|
setActiveButton(navLayoutButtons, "navLayout", activePreferences.navLayout);
|
||||||
setActiveButton(viewButtons, "view", activePreferences.view);
|
setActiveButton(viewButtons, "view", activePreferences.view);
|
||||||
setActiveButton(accentButtons, "accent", activePreferences.accent);
|
setActiveButton(accentButtons, "accent", activePreferences.accent);
|
||||||
|
syncPatternTargetPanels(activePreferences);
|
||||||
setActiveButton(treeMetaLayoutButtons, "treeMetaLayout", activePreferences.treeMetaLayout);
|
setActiveButton(treeMetaLayoutButtons, "treeMetaLayout", activePreferences.treeMetaLayout);
|
||||||
syncLayoutLimitInputs(activePreferences);
|
syncLayoutLimitInputs(activePreferences);
|
||||||
syncCatalogColumnInputs(activePreferences);
|
syncCatalogColumnInputs(activePreferences);
|
||||||
|
syncSettingsPanelWidthInput(activePreferences);
|
||||||
applyPanelFeatures(activePreferences);
|
applyPanelFeatures(activePreferences);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1524,7 +1633,11 @@ function isSettingsSectionVisible(sectionName, activePreferences) {
|
|||||||
case "tree":
|
case "tree":
|
||||||
return panelFeatures.allowTreeOptions && activePreferences.showTree;
|
return panelFeatures.allowTreeOptions && activePreferences.showTree;
|
||||||
case "appearance":
|
case "appearance":
|
||||||
return panelFeatures.allowThemeChange || panelFeatures.allowAccentChange;
|
return (
|
||||||
|
panelFeatures.allowThemeChange ||
|
||||||
|
panelFeatures.allowAccentChange ||
|
||||||
|
panelFeatures.allowPanelPatternChange
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1776,6 +1889,22 @@ function syncLayoutLimitInputs(activePreferences) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function syncSettingsPanelWidthInput(activePreferences) {
|
||||||
|
if (!settingsPanelWidthInput) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const limits = getPanelLimitRange("settingsPanelWidth");
|
||||||
|
settingsPanelWidthInput.min = String(limits.min);
|
||||||
|
settingsPanelWidthInput.max = String(limits.max);
|
||||||
|
settingsPanelWidthInput.step = "10";
|
||||||
|
settingsPanelWidthInput.value = String(activePreferences.settingsPanelWidth);
|
||||||
|
|
||||||
|
if (settingsPanelWidthValue) {
|
||||||
|
settingsPanelWidthValue.textContent = `${activePreferences.settingsPanelWidth}px`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function syncCatalogColumnInputs(activePreferences) {
|
function syncCatalogColumnInputs(activePreferences) {
|
||||||
catalogColumnInputs.forEach((input) => {
|
catalogColumnInputs.forEach((input) => {
|
||||||
const key = input.dataset.catalogColumns;
|
const key = input.dataset.catalogColumns;
|
||||||
@ -1802,6 +1931,194 @@ function getPanelLimitRange(key) {
|
|||||||
return getLayoutLimitRange(key);
|
return getLayoutLimitRange(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clampPanelPatternPercent(value, fallback = 50) {
|
||||||
|
const numeric = Number(value);
|
||||||
|
const base = Number.isFinite(numeric) ? numeric : fallback;
|
||||||
|
return clamp(Math.round(base), 0, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPanelPatternPreferenceKey(target, field) {
|
||||||
|
const cap = capitalizePanelPatternTarget(target);
|
||||||
|
|
||||||
|
switch (field) {
|
||||||
|
case "pattern":
|
||||||
|
return `panelPattern${cap}`;
|
||||||
|
case "opacity":
|
||||||
|
return `panelPattern${cap}Opacity`;
|
||||||
|
case "height":
|
||||||
|
return `panelPattern${cap}Height`;
|
||||||
|
case "fade":
|
||||||
|
return `panelPattern${cap}Fade`;
|
||||||
|
case "gradientOpacity":
|
||||||
|
return `panelPattern${cap}GradientOpacity`;
|
||||||
|
case "gradientHeight":
|
||||||
|
return `panelPattern${cap}GradientHeight`;
|
||||||
|
case "gradientFade":
|
||||||
|
return `panelPattern${cap}GradientFade`;
|
||||||
|
default:
|
||||||
|
return `panelPattern${cap}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function migrateLegacyPanelPatternPreferences(next) {
|
||||||
|
if (next.panelPatternNav !== undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const legacyPattern = availablePanelPatterns.includes(next.panelPattern)
|
||||||
|
? next.panelPattern
|
||||||
|
: panelPatternTargetMeta.nav.defaultPattern;
|
||||||
|
const legacyOpacity = next.panelPatternOpacity ?? panelPatternTuningDefaults.opacity;
|
||||||
|
const legacyHeight = next.panelPatternHeight ?? panelPatternTuningDefaults.height;
|
||||||
|
const legacyGradientOpacity = next.panelGradientOpacity ?? panelPatternTuningDefaults.gradientOpacity;
|
||||||
|
const legacyGradientHeight = next.panelGradientHeight ?? panelPatternTuningDefaults.gradientHeight;
|
||||||
|
const legacyTargets = [
|
||||||
|
["Nav", next.panelPatternOnNav !== false],
|
||||||
|
["Section", next.panelPatternOnSection !== false],
|
||||||
|
["Group", Boolean(next.panelPatternOnGroup)],
|
||||||
|
["Item", Boolean(next.panelPatternOnItem)],
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const [suffix, enabled] of legacyTargets) {
|
||||||
|
next[`panelPattern${suffix}`] = enabled && legacyPattern !== "none" ? legacyPattern : "none";
|
||||||
|
next[`panelPattern${suffix}Opacity`] = legacyOpacity;
|
||||||
|
next[`panelPattern${suffix}Height`] = legacyHeight;
|
||||||
|
next[`panelPattern${suffix}Fade`] = panelPatternTuningDefaults.fade;
|
||||||
|
next[`panelPattern${suffix}GradientOpacity`] = legacyGradientOpacity;
|
||||||
|
next[`panelPattern${suffix}GradientHeight`] = legacyGradientHeight;
|
||||||
|
next[`panelPattern${suffix}GradientFade`] = panelPatternTuningDefaults.gradientFade;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizePanelPatternPreferences(next) {
|
||||||
|
for (const target of panelPatternTargetIds) {
|
||||||
|
const cap = capitalizePanelPatternTarget(target);
|
||||||
|
const patternKey = `panelPattern${cap}`;
|
||||||
|
|
||||||
|
if (!availablePanelPatterns.includes(next[patternKey])) {
|
||||||
|
next[patternKey] = panelPatternTargetMeta[target].defaultPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
next[`panelPattern${cap}Opacity`] = clampPanelPatternPercent(
|
||||||
|
next[`panelPattern${cap}Opacity`],
|
||||||
|
panelPatternTuningDefaults.opacity,
|
||||||
|
);
|
||||||
|
next[`panelPattern${cap}Height`] = clampPanelPatternPercent(
|
||||||
|
next[`panelPattern${cap}Height`],
|
||||||
|
panelPatternTuningDefaults.height,
|
||||||
|
);
|
||||||
|
next[`panelPattern${cap}Fade`] = clampPanelPatternPercent(
|
||||||
|
next[`panelPattern${cap}Fade`],
|
||||||
|
panelPatternTuningDefaults.fade,
|
||||||
|
);
|
||||||
|
next[`panelPattern${cap}GradientOpacity`] = clampPanelPatternPercent(
|
||||||
|
next[`panelPattern${cap}GradientOpacity`],
|
||||||
|
panelPatternTuningDefaults.gradientOpacity,
|
||||||
|
);
|
||||||
|
next[`panelPattern${cap}GradientHeight`] = clampPanelPatternPercent(
|
||||||
|
next[`panelPattern${cap}GradientHeight`],
|
||||||
|
panelPatternTuningDefaults.gradientHeight,
|
||||||
|
);
|
||||||
|
next[`panelPattern${cap}GradientFade`] = clampPanelPatternPercent(
|
||||||
|
next[`panelPattern${cap}GradientFade`],
|
||||||
|
panelPatternTuningDefaults.gradientFade,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPanelPatternFadeStart(heightPercent, fadePercent) {
|
||||||
|
const height = clampPanelPatternPercent(heightPercent, panelPatternTuningDefaults.height);
|
||||||
|
const fade = clampPanelPatternPercent(fadePercent, panelPatternTuningDefaults.fade);
|
||||||
|
return `${Math.max(0, height - fade)}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyPanelPatternPreferences(activePreferences) {
|
||||||
|
for (const target of panelPatternTargetIds) {
|
||||||
|
const cap = capitalizePanelPatternTarget(target);
|
||||||
|
const pattern = activePreferences[`panelPattern${cap}`] || "none";
|
||||||
|
const height = clampPanelPatternPercent(
|
||||||
|
activePreferences[`panelPattern${cap}Height`],
|
||||||
|
panelPatternTuningDefaults.height,
|
||||||
|
);
|
||||||
|
const opacityPercent = clampPanelPatternPercent(
|
||||||
|
activePreferences[`panelPattern${cap}Opacity`],
|
||||||
|
panelPatternTuningDefaults.opacity,
|
||||||
|
);
|
||||||
|
const patternOpacity = pattern === "none" || height === 0 ? 0 : opacityPercent / 100;
|
||||||
|
|
||||||
|
document.documentElement.dataset[`panelPattern${cap}`] = pattern;
|
||||||
|
document.documentElement.style.setProperty(`--panel-pattern-${target}-opacity`, String(patternOpacity));
|
||||||
|
document.documentElement.style.setProperty(`--panel-pattern-${target}-height`, `${height}%`);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
`--panel-pattern-${target}-fade-start`,
|
||||||
|
getPanelPatternFadeStart(height, activePreferences[`panelPattern${cap}Fade`]),
|
||||||
|
);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
`--panel-gradient-${target}-strength`,
|
||||||
|
String(
|
||||||
|
(clampPanelPatternPercent(
|
||||||
|
activePreferences[`panelPattern${cap}GradientOpacity`],
|
||||||
|
panelPatternTuningDefaults.gradientOpacity,
|
||||||
|
) /
|
||||||
|
100) *
|
||||||
|
0.28,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const gradientHeight = clampPanelPatternPercent(
|
||||||
|
activePreferences[`panelPattern${cap}GradientHeight`],
|
||||||
|
panelPatternTuningDefaults.gradientHeight,
|
||||||
|
);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
`--panel-gradient-${target}-height`,
|
||||||
|
`${gradientHeight}%`,
|
||||||
|
);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
`--panel-gradient-${target}-fade-start`,
|
||||||
|
getPanelPatternFadeStart(gradientHeight, activePreferences[`panelPattern${cap}GradientFade`]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncPatternTargetPanels(activePreferences) {
|
||||||
|
if (!patternTargetsPanel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const disabled = !panelFeatures.allowPanelPatternChange;
|
||||||
|
const tuningFields = ["opacity", "height", "fade", "gradientOpacity", "gradientHeight", "gradientFade"];
|
||||||
|
|
||||||
|
for (const target of panelPatternTargetIds) {
|
||||||
|
const pattern = activePreferences[getPanelPatternPreferenceKey(target, "pattern")];
|
||||||
|
patternTargetsPanel
|
||||||
|
.querySelectorAll(`[data-panel-pattern-target="${target}"][data-panel-pattern]`)
|
||||||
|
.forEach((button) => {
|
||||||
|
const isActive = button.dataset.panelPattern === pattern;
|
||||||
|
button.classList.toggle("is-active", isActive);
|
||||||
|
button.setAttribute("aria-pressed", String(isActive));
|
||||||
|
button.disabled = disabled;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const field of tuningFields) {
|
||||||
|
const key = getPanelPatternPreferenceKey(target, field);
|
||||||
|
const input = patternTargetsPanel.querySelector(
|
||||||
|
`[data-panel-pattern-tuning="${target}"][data-panel-pattern-field="${field}"]`,
|
||||||
|
);
|
||||||
|
const output = patternTargetsPanel.querySelector(
|
||||||
|
`[data-panel-pattern-value="${target}"][data-panel-pattern-field="${field}"]`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (input) {
|
||||||
|
input.value = String(activePreferences[key]);
|
||||||
|
input.disabled = disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output) {
|
||||||
|
output.textContent = `${activePreferences[key]}%`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function clampCatalogColumn(key, value) {
|
function clampCatalogColumn(key, value) {
|
||||||
const limits = getPanelLimitRange(key);
|
const limits = getPanelLimitRange(key);
|
||||||
const fallback = panelDefaults[key] ?? defaultPreferences[key];
|
const fallback = panelDefaults[key] ?? defaultPreferences[key];
|
||||||
|
|||||||
@ -11,6 +11,26 @@
|
|||||||
"customAccentFrom": "#8b5cf6",
|
"customAccentFrom": "#8b5cf6",
|
||||||
"customAccentTo": "#22d3ee",
|
"customAccentTo": "#22d3ee",
|
||||||
"customAccentAngle": 135,
|
"customAccentAngle": 135,
|
||||||
|
"panelPatternNav": "hex",
|
||||||
|
"panelPatternNavOpacity": 70,
|
||||||
|
"panelPatternNavHeight": 45,
|
||||||
|
"panelPatternNavGradientOpacity": 80,
|
||||||
|
"panelPatternNavGradientHeight": 40,
|
||||||
|
"panelPatternSection": "hex",
|
||||||
|
"panelPatternSectionOpacity": 70,
|
||||||
|
"panelPatternSectionHeight": 45,
|
||||||
|
"panelPatternSectionGradientOpacity": 80,
|
||||||
|
"panelPatternSectionGradientHeight": 40,
|
||||||
|
"panelPatternGroup": "none",
|
||||||
|
"panelPatternGroupOpacity": 70,
|
||||||
|
"panelPatternGroupHeight": 45,
|
||||||
|
"panelPatternGroupGradientOpacity": 80,
|
||||||
|
"panelPatternGroupGradientHeight": 40,
|
||||||
|
"panelPatternItem": "none",
|
||||||
|
"panelPatternItemOpacity": 70,
|
||||||
|
"panelPatternItemHeight": 45,
|
||||||
|
"panelPatternItemGradientOpacity": 80,
|
||||||
|
"panelPatternItemGradientHeight": 40,
|
||||||
"showNumbers": false,
|
"showNumbers": false,
|
||||||
"showTreeTags": true,
|
"showTreeTags": true,
|
||||||
"showTreeType": false,
|
"showTreeType": false,
|
||||||
@ -31,7 +51,8 @@
|
|||||||
"catalogListColumns": 1,
|
"catalogListColumns": 1,
|
||||||
"catalogCompactCardsColumns": 5,
|
"catalogCompactCardsColumns": 5,
|
||||||
"catalogCompactListColumns": 3,
|
"catalogCompactListColumns": 3,
|
||||||
"searchPlaceholder": "Grafana, S3, журнал, сервер..."
|
"searchPlaceholder": "Grafana, S3, журнал, сервер...",
|
||||||
|
"settingsPanelWidth": 460
|
||||||
},
|
},
|
||||||
"limits": {
|
"limits": {
|
||||||
"shellMaxWidth": { "min": 1200, "max": 3840 },
|
"shellMaxWidth": { "min": 1200, "max": 3840 },
|
||||||
@ -45,7 +66,8 @@
|
|||||||
"catalogCardsColumns": { "min": 1, "max": 6 },
|
"catalogCardsColumns": { "min": 1, "max": 6 },
|
||||||
"catalogListColumns": { "min": 1, "max": 4 },
|
"catalogListColumns": { "min": 1, "max": 4 },
|
||||||
"catalogCompactCardsColumns": { "min": 2, "max": 8 },
|
"catalogCompactCardsColumns": { "min": 2, "max": 8 },
|
||||||
"catalogCompactListColumns": { "min": 1, "max": 6 }
|
"catalogCompactListColumns": { "min": 1, "max": 6 },
|
||||||
|
"settingsPanelWidth": { "min": 320, "max": 720 }
|
||||||
},
|
},
|
||||||
"features": {
|
"features": {
|
||||||
"allowNavLayoutChange": true,
|
"allowNavLayoutChange": true,
|
||||||
@ -58,6 +80,7 @@
|
|||||||
"allowSidebarResize": true,
|
"allowSidebarResize": true,
|
||||||
"allowLayoutLimitsChange": true,
|
"allowLayoutLimitsChange": true,
|
||||||
"allowThemeChange": true,
|
"allowThemeChange": true,
|
||||||
"allowAccentChange": true
|
"allowAccentChange": true,
|
||||||
|
"allowPanelPatternChange": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
373
styles.css
373
styles.css
@ -31,6 +31,46 @@
|
|||||||
--catalog-list-columns: 1;
|
--catalog-list-columns: 1;
|
||||||
--catalog-compact-cards-columns: 5;
|
--catalog-compact-cards-columns: 5;
|
||||||
--catalog-compact-list-columns: 3;
|
--catalog-compact-list-columns: 3;
|
||||||
|
--pattern-color: rgba(255, 255, 255, 0.16);
|
||||||
|
--pattern-tile-hex-image: url("data:image/svg+xml,%3Csvg width='96' height='84' viewBox='0 0 96 84' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' stroke='white' stroke-opacity='.18' stroke-width='1.4'%3E%3Cpath d='M24 2 46 14v25L24 52 2 39V14L24 2Z'/%3E%3Cpath d='M72 32 94 44v25L72 82 50 69V44l22-12Z'/%3E%3C/g%3E%3C/svg%3E");
|
||||||
|
--pattern-tile-hex-size: 96px 84px;
|
||||||
|
--pattern-tile-dots-image: radial-gradient(circle at center, var(--pattern-color) 0.95px, transparent 1px);
|
||||||
|
--pattern-tile-dots-size: 18px 18px;
|
||||||
|
--pattern-tile-grid-image:
|
||||||
|
linear-gradient(var(--pattern-color) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, var(--pattern-color) 1px, transparent 1px);
|
||||||
|
--pattern-tile-grid-size: 26px 26px;
|
||||||
|
--pattern-tile-diagonal-image: repeating-linear-gradient(
|
||||||
|
-45deg,
|
||||||
|
transparent,
|
||||||
|
transparent 10px,
|
||||||
|
var(--pattern-color) 10px,
|
||||||
|
var(--pattern-color) 11px
|
||||||
|
);
|
||||||
|
--pattern-tile-diagonal-size: auto;
|
||||||
|
--pattern-tile-cross-image:
|
||||||
|
repeating-linear-gradient(
|
||||||
|
0deg,
|
||||||
|
transparent,
|
||||||
|
transparent 14px,
|
||||||
|
var(--pattern-color) 14px,
|
||||||
|
var(--pattern-color) 15px
|
||||||
|
),
|
||||||
|
repeating-linear-gradient(
|
||||||
|
90deg,
|
||||||
|
transparent,
|
||||||
|
transparent 14px,
|
||||||
|
var(--pattern-color) 14px,
|
||||||
|
var(--pattern-color) 15px
|
||||||
|
);
|
||||||
|
--pattern-tile-cross-size: auto;
|
||||||
|
--pattern-tile-mesh-image: radial-gradient(
|
||||||
|
circle at 1px 1px,
|
||||||
|
rgba(var(--accent-rgb), 0.22) 1px,
|
||||||
|
transparent 0
|
||||||
|
);
|
||||||
|
--pattern-tile-mesh-size: 20px 20px;
|
||||||
|
--settings-panel-width: 460px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Светлая тема переопределяет только токены, структура стилей остается общей. */
|
/* Светлая тема переопределяет только токены, структура стилей остается общей. */
|
||||||
@ -45,8 +85,40 @@ html[data-theme="light"] {
|
|||||||
--muted: #5f6b7a;
|
--muted: #5f6b7a;
|
||||||
--border: rgba(15, 23, 42, 0.12);
|
--border: rgba(15, 23, 42, 0.12);
|
||||||
--shadow: 0 24px 70px rgba(56, 65, 91, 0.18);
|
--shadow: 0 24px 70px rgba(56, 65, 91, 0.18);
|
||||||
|
--pattern-color: rgba(15, 23, 42, 0.13);
|
||||||
|
--pattern-tile-hex-image: url("data:image/svg+xml,%3Csvg width='96' height='84' viewBox='0 0 96 84' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' stroke='%23101827' stroke-opacity='.14' stroke-width='1.4'%3E%3Cpath d='M24 2 46 14v25L24 52 2 39V14L24 2Z'/%3E%3Cpath d='M72 32 94 44v25L72 82 50 69V44l22-12Z'/%3E%3C/g%3E%3C/svg%3E");
|
||||||
|
--pattern-tile-mesh-image: radial-gradient(
|
||||||
|
circle at 1px 1px,
|
||||||
|
rgba(var(--accent-rgb), 0.16) 1px,
|
||||||
|
transparent 0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html[data-panel-pattern-nav="hex"] { --panel-pattern-image-nav: var(--pattern-tile-hex-image); --panel-pattern-size-nav: var(--pattern-tile-hex-size); }
|
||||||
|
html[data-panel-pattern-nav="dots"] { --panel-pattern-image-nav: var(--pattern-tile-dots-image); --panel-pattern-size-nav: var(--pattern-tile-dots-size); }
|
||||||
|
html[data-panel-pattern-nav="grid"] { --panel-pattern-image-nav: var(--pattern-tile-grid-image); --panel-pattern-size-nav: var(--pattern-tile-grid-size); }
|
||||||
|
html[data-panel-pattern-nav="diagonal"] { --panel-pattern-image-nav: var(--pattern-tile-diagonal-image); --panel-pattern-size-nav: var(--pattern-tile-diagonal-size); }
|
||||||
|
html[data-panel-pattern-nav="cross"] { --panel-pattern-image-nav: var(--pattern-tile-cross-image); --panel-pattern-size-nav: var(--pattern-tile-cross-size); }
|
||||||
|
html[data-panel-pattern-nav="mesh"] { --panel-pattern-image-nav: var(--pattern-tile-mesh-image); --panel-pattern-size-nav: var(--pattern-tile-mesh-size); }
|
||||||
|
html[data-panel-pattern-section="hex"] { --panel-pattern-image-section: var(--pattern-tile-hex-image); --panel-pattern-size-section: var(--pattern-tile-hex-size); }
|
||||||
|
html[data-panel-pattern-section="dots"] { --panel-pattern-image-section: var(--pattern-tile-dots-image); --panel-pattern-size-section: var(--pattern-tile-dots-size); }
|
||||||
|
html[data-panel-pattern-section="grid"] { --panel-pattern-image-section: var(--pattern-tile-grid-image); --panel-pattern-size-section: var(--pattern-tile-grid-size); }
|
||||||
|
html[data-panel-pattern-section="diagonal"] { --panel-pattern-image-section: var(--pattern-tile-diagonal-image); --panel-pattern-size-section: var(--pattern-tile-diagonal-size); }
|
||||||
|
html[data-panel-pattern-section="cross"] { --panel-pattern-image-section: var(--pattern-tile-cross-image); --panel-pattern-size-section: var(--pattern-tile-cross-size); }
|
||||||
|
html[data-panel-pattern-section="mesh"] { --panel-pattern-image-section: var(--pattern-tile-mesh-image); --panel-pattern-size-section: var(--pattern-tile-mesh-size); }
|
||||||
|
html[data-panel-pattern-group="hex"] { --panel-pattern-image-group: var(--pattern-tile-hex-image); --panel-pattern-size-group: var(--pattern-tile-hex-size); }
|
||||||
|
html[data-panel-pattern-group="dots"] { --panel-pattern-image-group: var(--pattern-tile-dots-image); --panel-pattern-size-group: var(--pattern-tile-dots-size); }
|
||||||
|
html[data-panel-pattern-group="grid"] { --panel-pattern-image-group: var(--pattern-tile-grid-image); --panel-pattern-size-group: var(--pattern-tile-grid-size); }
|
||||||
|
html[data-panel-pattern-group="diagonal"] { --panel-pattern-image-group: var(--pattern-tile-diagonal-image); --panel-pattern-size-group: var(--pattern-tile-diagonal-size); }
|
||||||
|
html[data-panel-pattern-group="cross"] { --panel-pattern-image-group: var(--pattern-tile-cross-image); --panel-pattern-size-group: var(--pattern-tile-cross-size); }
|
||||||
|
html[data-panel-pattern-group="mesh"] { --panel-pattern-image-group: var(--pattern-tile-mesh-image); --panel-pattern-size-group: var(--pattern-tile-mesh-size); }
|
||||||
|
html[data-panel-pattern-item="hex"] { --panel-pattern-image-item: var(--pattern-tile-hex-image); --panel-pattern-size-item: var(--pattern-tile-hex-size); }
|
||||||
|
html[data-panel-pattern-item="dots"] { --panel-pattern-image-item: var(--pattern-tile-dots-image); --panel-pattern-size-item: var(--pattern-tile-dots-size); }
|
||||||
|
html[data-panel-pattern-item="grid"] { --panel-pattern-image-item: var(--pattern-tile-grid-image); --panel-pattern-size-item: var(--pattern-tile-grid-size); }
|
||||||
|
html[data-panel-pattern-item="diagonal"] { --panel-pattern-image-item: var(--pattern-tile-diagonal-image); --panel-pattern-size-item: var(--pattern-tile-diagonal-size); }
|
||||||
|
html[data-panel-pattern-item="cross"] { --panel-pattern-image-item: var(--pattern-tile-cross-image); --panel-pattern-size-item: var(--pattern-tile-cross-size); }
|
||||||
|
html[data-panel-pattern-item="mesh"] { --panel-pattern-image-item: var(--pattern-tile-mesh-image); --panel-pattern-size-item: var(--pattern-tile-mesh-size); }
|
||||||
|
|
||||||
/* Наборы акцентов. --accent-rgb нужен для прозрачных градиентов через rgba(). */
|
/* Наборы акцентов. --accent-rgb нужен для прозрачных градиентов через rgba(). */
|
||||||
html[data-accent="cyan"] {
|
html[data-accent="cyan"] {
|
||||||
--accent: #06b6d4;
|
--accent: #06b6d4;
|
||||||
@ -324,6 +396,8 @@ body.is-resizing-top-bar {
|
|||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
box-shadow: var(--shadow);
|
box-shadow: var(--shadow);
|
||||||
backdrop-filter: blur(22px);
|
backdrop-filter: blur(22px);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-content {
|
.hero-content {
|
||||||
@ -335,7 +409,6 @@ body.is-resizing-top-bar {
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding: clamp(16px, 2.6vw, 24px);
|
padding: clamp(16px, 2.6vw, 24px);
|
||||||
border-radius: 22px;
|
border-radius: 22px;
|
||||||
position: relative;
|
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,21 +417,117 @@ body.is-resizing-top-bar {
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Внутренний фон sidebar: градиент + hexagon pattern. */
|
/* Акцентный градиент под узором — отдельно для каждого типа блоков. */
|
||||||
.hero-content::before {
|
html:not([data-panel-pattern-nav="none"]) .hero-content::before {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
border-radius: inherit;
|
border-radius: inherit;
|
||||||
background:
|
background: linear-gradient(120deg, rgba(var(--accent-rgb), 1), transparent 38%);
|
||||||
linear-gradient(120deg, rgba(var(--accent-rgb), 0.25), transparent 34%),
|
opacity: var(--panel-gradient-nav-strength);
|
||||||
url("data:image/svg+xml,%3Csvg width='96' height='84' viewBox='0 0 96 84' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' stroke='white' stroke-opacity='.10' stroke-width='1.4'%3E%3Cpath d='M24 2 46 14v25L24 52 2 39V14L24 2Z'/%3E%3Cpath d='M72 32 94 44v25L72 82 50 69V44l22-12Z'/%3E%3C/g%3E%3C/svg%3E");
|
mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-gradient-nav-fade-start), transparent var(--panel-gradient-nav-height));
|
||||||
mask-image: linear-gradient(to bottom, black, transparent 88%);
|
-webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-gradient-nav-fade-start), transparent var(--panel-gradient-nav-height));
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html:not([data-panel-pattern-section="none"]) .catalog-section::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
background: linear-gradient(120deg, rgba(var(--accent-rgb), 1), transparent 38%);
|
||||||
|
opacity: var(--panel-gradient-section-strength);
|
||||||
|
mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-gradient-section-fade-start), transparent var(--panel-gradient-section-height));
|
||||||
|
-webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-gradient-section-fade-start), transparent var(--panel-gradient-section-height));
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html:not([data-panel-pattern-group="none"]) .catalog-group::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
background: linear-gradient(120deg, rgba(var(--accent-rgb), 1), transparent 38%);
|
||||||
|
opacity: var(--panel-gradient-group-strength);
|
||||||
|
mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-gradient-group-fade-start), transparent var(--panel-gradient-group-height));
|
||||||
|
-webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-gradient-group-fade-start), transparent var(--panel-gradient-group-height));
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html:not([data-panel-pattern-nav="none"]) .hero-content::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
opacity: var(--panel-pattern-nav-opacity);
|
||||||
|
background-image: var(--panel-pattern-image-nav);
|
||||||
|
background-size: var(--panel-pattern-size-nav);
|
||||||
|
background-repeat: repeat;
|
||||||
|
mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-pattern-nav-fade-start), transparent var(--panel-pattern-nav-height));
|
||||||
|
-webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-pattern-nav-fade-start), transparent var(--panel-pattern-nav-height));
|
||||||
|
}
|
||||||
|
|
||||||
|
html:not([data-panel-pattern-section="none"]) .catalog-section::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
opacity: var(--panel-pattern-section-opacity);
|
||||||
|
background-image: var(--panel-pattern-image-section);
|
||||||
|
background-size: var(--panel-pattern-size-section);
|
||||||
|
background-repeat: repeat;
|
||||||
|
mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-pattern-section-fade-start), transparent var(--panel-pattern-section-height));
|
||||||
|
-webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-pattern-section-fade-start), transparent var(--panel-pattern-section-height));
|
||||||
|
}
|
||||||
|
|
||||||
|
html:not([data-panel-pattern-group="none"]) .catalog-group::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
opacity: var(--panel-pattern-group-opacity);
|
||||||
|
background-image: var(--panel-pattern-image-group);
|
||||||
|
background-size: var(--panel-pattern-size-group);
|
||||||
|
background-repeat: repeat;
|
||||||
|
mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-pattern-group-fade-start), transparent var(--panel-pattern-group-height));
|
||||||
|
-webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-pattern-group-fade-start), transparent var(--panel-pattern-group-height));
|
||||||
|
}
|
||||||
|
|
||||||
|
html:not([data-panel-pattern-item="none"]) .nav-card::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
opacity: var(--panel-pattern-item-opacity);
|
||||||
|
background-image: var(--panel-pattern-image-item);
|
||||||
|
background-size: var(--panel-pattern-size-item);
|
||||||
|
background-repeat: repeat;
|
||||||
|
mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-pattern-item-fade-start), transparent var(--panel-pattern-item-height));
|
||||||
|
-webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 var(--panel-pattern-item-fade-start), transparent var(--panel-pattern-item-height));
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog-section > summary,
|
||||||
|
.catalog-section > .section-groups,
|
||||||
|
.catalog-group > summary,
|
||||||
|
.catalog-group > .items-grid {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-content > * {
|
.hero-content > * {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Общий стиль маленьких uppercase-меток и номеров. */
|
/* Общий стиль маленьких uppercase-меток и номеров. */
|
||||||
@ -414,7 +583,7 @@ html[data-show-tree-tags="false"][data-show-tree-type="false"] .tree-file-meta {
|
|||||||
z-index: 1001;
|
z-index: 1001;
|
||||||
top: 24px;
|
top: 24px;
|
||||||
right: 24px;
|
right: 24px;
|
||||||
width: min(460px, calc(100% - 48px));
|
width: min(var(--settings-panel-width), calc(100% - 48px));
|
||||||
max-height: calc(100vh - 48px);
|
max-height: calc(100vh - 48px);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -512,6 +681,27 @@ html[data-show-tree-tags="false"][data-show-tree-type="false"] .tree-file-meta {
|
|||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.settings-width-row {
|
||||||
|
grid-template-columns: minmax(0, 1fr) auto;
|
||||||
|
grid-template-rows: auto auto;
|
||||||
|
gap: 6px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-width-row span {
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-width-row output {
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-width-row input[type="range"] {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
grid-row: 2;
|
||||||
|
}
|
||||||
|
|
||||||
.settings-section {
|
.settings-section {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
@ -901,6 +1091,166 @@ html[data-theme="light"] .accent-swatch-custom {
|
|||||||
transform: scale(1.05);
|
transform: scale(1.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pattern-group {
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-targets-panel {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-target-panel .settings-section-body {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatches {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 8px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch {
|
||||||
|
min-height: 54px;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 14px;
|
||||||
|
background: var(--surface);
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
opacity: 0.95;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch[data-panel-pattern="none"]::before {
|
||||||
|
background: linear-gradient(135deg, rgba(var(--accent-rgb), 0.12), transparent 70%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch[data-panel-pattern="hex"]::before {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg width='96' height='84' viewBox='0 0 96 84' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' stroke='white' stroke-opacity='.18' stroke-width='1.4'%3E%3Cpath d='M24 2 46 14v25L24 52 2 39V14L24 2Z'/%3E%3Cpath d='M72 32 94 44v25L72 82 50 69V44l22-12Z'/%3E%3C/g%3E%3C/svg%3E");
|
||||||
|
background-size: 48px 42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme="light"] .pattern-swatch[data-panel-pattern="hex"]::before {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg width='96' height='84' viewBox='0 0 96 84' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' stroke='%23101827' stroke-opacity='.14' stroke-width='1.4'%3E%3Cpath d='M24 2 46 14v25L24 52 2 39V14L24 2Z'/%3E%3Cpath d='M72 32 94 44v25L72 82 50 69V44l22-12Z'/%3E%3C/g%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch[data-panel-pattern="dots"]::before {
|
||||||
|
background-image: radial-gradient(circle at center, var(--pattern-color) 0.95px, transparent 1px);
|
||||||
|
background-size: 12px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch[data-panel-pattern="grid"]::before {
|
||||||
|
background-image:
|
||||||
|
linear-gradient(var(--pattern-color) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, var(--pattern-color) 1px, transparent 1px);
|
||||||
|
background-size: 16px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch[data-panel-pattern="diagonal"]::before {
|
||||||
|
background-image: repeating-linear-gradient(
|
||||||
|
-45deg,
|
||||||
|
transparent,
|
||||||
|
transparent 7px,
|
||||||
|
var(--pattern-color) 7px,
|
||||||
|
var(--pattern-color) 8px
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch[data-panel-pattern="cross"]::before {
|
||||||
|
background-image:
|
||||||
|
repeating-linear-gradient(
|
||||||
|
0deg,
|
||||||
|
transparent,
|
||||||
|
transparent 9px,
|
||||||
|
var(--pattern-color) 9px,
|
||||||
|
var(--pattern-color) 10px
|
||||||
|
),
|
||||||
|
repeating-linear-gradient(
|
||||||
|
90deg,
|
||||||
|
transparent,
|
||||||
|
transparent 9px,
|
||||||
|
var(--pattern-color) 9px,
|
||||||
|
var(--pattern-color) 10px
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch[data-panel-pattern="mesh"]::before {
|
||||||
|
background-image: radial-gradient(
|
||||||
|
circle at 1px 1px,
|
||||||
|
rgba(var(--accent-rgb), 0.24) 1px,
|
||||||
|
transparent 0
|
||||||
|
);
|
||||||
|
background-size: 12px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch-label {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
display: grid;
|
||||||
|
place-items: end start;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 6px 8px;
|
||||||
|
background: linear-gradient(to top, rgba(0, 0, 0, 0.28), transparent 58%);
|
||||||
|
color: #f8fafc;
|
||||||
|
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme="light"] .pattern-swatch-label {
|
||||||
|
background: linear-gradient(to top, rgba(255, 255, 255, 0.82), transparent 58%);
|
||||||
|
color: #101827;
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-swatch.is-active {
|
||||||
|
border-color: rgba(var(--accent-rgb), 0.72);
|
||||||
|
box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-tuning {
|
||||||
|
display: grid;
|
||||||
|
gap: 12px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-tuning .accent-custom-row {
|
||||||
|
grid-template-columns: minmax(0, 1fr) auto;
|
||||||
|
grid-template-rows: auto auto;
|
||||||
|
gap: 6px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-tuning .accent-custom-row span {
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-tuning .accent-custom-row output {
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern-tuning .accent-custom-row input[type="range"] {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
grid-row: 2;
|
||||||
|
}
|
||||||
|
|
||||||
/* Панель настройки своего градиента появляется при data-accent="custom". */
|
/* Панель настройки своего градиента появляется при data-accent="custom". */
|
||||||
.accent-custom-panel {
|
.accent-custom-panel {
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -1329,6 +1679,7 @@ html:not([data-tree-columns="1"]) .tree-node-icon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.catalog-group {
|
.catalog-group {
|
||||||
|
position: relative;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: 18px;
|
border-radius: 18px;
|
||||||
background: rgba(255, 255, 255, 0.035);
|
background: rgba(255, 255, 255, 0.035);
|
||||||
@ -1427,6 +1778,7 @@ html:not([data-tree-columns="1"]) .tree-node-icon {
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 180ms ease;
|
transition: opacity 180ms ease;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hover задается классом .is-hovered из JS, чтобы убрать скачки на границах. */
|
/* Hover задается классом .is-hovered из JS, чтобы убрать скачки на границах. */
|
||||||
@ -1445,6 +1797,8 @@ html:not([data-tree-columns="1"]) .tree-node-icon {
|
|||||||
|
|
||||||
/* Иконка сервиса берется из serviceMeta. */
|
/* Иконка сервиса берется из serviceMeta. */
|
||||||
.nav-card img {
|
.nav-card img {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
@ -1453,6 +1807,7 @@ html:not([data-tree-columns="1"]) .tree-node-icon {
|
|||||||
|
|
||||||
.card-content {
|
.card-content {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
}
|
}
|
||||||
@ -1493,6 +1848,7 @@ html:not([data-tree-columns="1"]) .tree-node-icon {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
right: 16px;
|
right: 16px;
|
||||||
bottom: 14px;
|
bottom: 14px;
|
||||||
|
z-index: 1;
|
||||||
width: 36px;
|
width: 36px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -1515,6 +1871,7 @@ html:not([data-tree-columns="1"]) .tree-node-icon {
|
|||||||
.shine {
|
.shine {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
|
z-index: 2;
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
110deg,
|
110deg,
|
||||||
transparent 0%,
|
transparent 0%,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user