feat: добавить кнопку выхода и улучшить интерфейс

- Добавлена кнопка выхода (sign-out-alt) в заголовок сайдбара
- Цветовая индикация состояния WebSocket: зеленый (on), красный (off), желтый (err)
- Удалена кнопка минимизации, оставлена только кнопка Options
- Кнопка Options по умолчанию свернута (настройки скрыты)
- Добавлено подтверждение при выходе
- Очистка localStorage при выходе
- Улучшенный дизайн кнопок с hover эффектами
- Максимальное пространство для списка контейнеров по умолчанию

Автор: Сергей Антропов
Сайт: https://devops.org.ru
This commit is contained in:
Сергей Антропов 2025-08-16 13:05:32 +03:00
parent 0af84ce0c3
commit 36eef6a08d

View File

@ -73,7 +73,7 @@ a{color:var(--link)}
} }
.options-btn, .options-btn,
.minimize-all-btn { .logout-btn {
background: var(--chip); background: var(--chip);
border: 1px solid var(--border); border: 1px solid var(--border);
color: var(--muted); color: var(--muted);
@ -87,7 +87,7 @@ a{color:var(--link)}
} }
.options-btn:hover, .options-btn:hover,
.minimize-all-btn:hover { .logout-btn:hover {
background: var(--tab-active); background: var(--tab-active);
color: var(--fg); color: var(--fg);
border-color: var(--accent); border-color: var(--accent);
@ -99,11 +99,33 @@ a{color:var(--link)}
border-color: var(--accent); border-color: var(--accent);
} }
.logout-btn:hover {
background: var(--err);
color: #fff;
border-color: var(--err);
}
.options-btn i, .options-btn i,
.minimize-all-btn i { .logout-btn i {
font-size: 12px; font-size: 12px;
} }
/* Цвета для ws состояния */
#wsstate.ws-on {
color: var(--ok);
font-weight: 500;
}
#wsstate.ws-off {
color: var(--err);
font-weight: 500;
}
#wsstate.ws-err {
color: var(--warn);
font-weight: 500;
}
/* Sidebar Controls */ /* Sidebar Controls */
.sidebar-controls { .sidebar-controls {
padding: 16px; padding: 16px;
@ -587,8 +609,8 @@ footer{position:fixed;right:10px;bottom:10px;opacity:.6;font-size:11px}
<button class="options-btn" id="optionsBtn" title="Показать/скрыть настройки"> <button class="options-btn" id="optionsBtn" title="Показать/скрыть настройки">
<i class="fas fa-cog"></i> <i class="fas fa-cog"></i>
</button> </button>
<button class="minimize-all-btn" id="minimizeAllBtn" title="Свернуть все секции"> <button class="logout-btn" id="logoutBtn" title="Выйти">
<i class="fas fa-compress-alt"></i> <i class="fas fa-sign-out-alt"></i>
</button> </button>
</div> </div>
</div> </div>
@ -805,8 +827,8 @@ const els = {
logTitle: document.getElementById('logTitle'), logTitle: document.getElementById('logTitle'),
logContent: document.getElementById('logContent'), logContent: document.getElementById('logContent'),
mobileToggle: document.getElementById('mobileToggle'), mobileToggle: document.getElementById('mobileToggle'),
minimizeAllBtn: document.getElementById('minimizeAllBtn'),
optionsBtn: document.getElementById('optionsBtn'), optionsBtn: document.getElementById('optionsBtn'),
logoutBtn: document.getElementById('logoutBtn'),
}; };
// ----- Theme toggle ----- // ----- Theme toggle -----
@ -821,7 +843,21 @@ const els = {
}); });
})(); })();
function setWsState(s){ els.wsstate.textContent = 'ws: ' + s; } function setWsState(s){
els.wsstate.textContent = 'ws: ' + s;
// Удаляем все классы состояний
els.wsstate.classList.remove('ws-on', 'ws-off', 'ws-err');
// Добавляем соответствующий класс
if (s === 'on') {
els.wsstate.classList.add('ws-on');
} else if (s === 'off') {
els.wsstate.classList.add('ws-off');
} else if (s === 'err') {
els.wsstate.classList.add('ws-err');
}
}
// Функция для обновления всех логов при изменении фильтров // Функция для обновления всех логов при изменении фильтров
function refreshAllLogs() { function refreshAllLogs() {
@ -1510,46 +1546,29 @@ document.addEventListener('DOMContentLoaded', () => {
} }
}); });
// Восстанавливаем состояние кнопки Options // Восстанавливаем состояние кнопки Options (по умолчанию скрыто)
const optionsHidden = localStorage.getItem('lb_options_hidden') === 'true'; const optionsHidden = localStorage.getItem('lb_options_hidden');
if (optionsHidden) { if (optionsHidden === null || optionsHidden === 'true') {
document.querySelector('.sidebar-controls').classList.add('hidden'); document.querySelector('.sidebar-controls').classList.add('hidden');
els.optionsBtn.classList.add('active'); els.optionsBtn.classList.add('active');
els.optionsBtn.title = 'Показать настройки'; els.optionsBtn.title = 'Показать настройки';
localStorage.setItem('lb_options_hidden', 'true');
} }
} }
// Обработчик для кнопки минимизации всех секций // Обработчик для кнопки выхода
if (els.minimizeAllBtn) { if (els.logoutBtn) {
els.minimizeAllBtn.addEventListener('click', () => { els.logoutBtn.addEventListener('click', () => {
const allMinimized = document.querySelectorAll('.control-group.collapsible').length === if (confirm('Вы уверены, что хотите выйти?')) {
document.querySelectorAll('.control-group.collapsible.minimized').length; // Очищаем localStorage
localStorage.clear();
// Перенаправляем на страницу входа
window.location.href = '/';
}
});
}
// Если все секции минимизированы, разворачиваем их
if (allMinimized) {
document.querySelectorAll('.control-group.collapsible').forEach(group => {
group.classList.remove('minimized');
group.classList.add('collapsed'); // Возвращаем к обычному свернутому состоянию
const section = group.dataset.section;
localStorage.setItem(`lb_collapsed_${section}`, 'true');
localStorage.setItem(`lb_minimized_${section}`, 'false');
});
els.minimizeAllBtn.innerHTML = '<i class="fas fa-compress-alt"></i>';
els.minimizeAllBtn.title = 'Минимизировать все секции';
} else {
// Иначе минимизируем все секции до полоски
document.querySelectorAll('.control-group.collapsible').forEach(group => {
group.classList.add('minimized');
group.classList.remove('collapsed');
const section = group.dataset.section;
localStorage.setItem(`lb_collapsed_${section}`, 'false');
localStorage.setItem(`lb_minimized_${section}`, 'true');
});
els.minimizeAllBtn.innerHTML = '<i class="fas fa-expand-alt"></i>';
els.minimizeAllBtn.title = 'Развернуть все секции';
}
});
}
}); });
els.snapshotBtn.onclick = ()=>{ els.snapshotBtn.onclick = ()=>{
if (state.current) { if (state.current) {