mirror of
https://github.com/infinition/Bjorn.git
synced 2026-03-14 16:32:05 +00:00
Add RLUtils class for managing RL/AI dashboard endpoints
- Implemented methods for fetching AI stats, training history, and recent experiences. - Added functionality to set operation mode (MANUAL, AUTO, AI) with appropriate handling. - Included helper methods for querying the database and sending JSON responses. - Integrated model metadata extraction for visualization purposes.
This commit is contained in:
131
web/js/core/sidebar-layout.js
Normal file
131
web/js/core/sidebar-layout.js
Normal file
@@ -0,0 +1,131 @@
|
||||
import { t } from './i18n.js';
|
||||
|
||||
/**
|
||||
* Shared page sidebar layout controller.
|
||||
* Provides one common desktop/mobile behavior for pages with left sidebars.
|
||||
*/
|
||||
|
||||
export function initSharedSidebarLayout(root, opts = {}) {
|
||||
if (!root) return () => { };
|
||||
|
||||
const sidebarSelector = opts.sidebarSelector || '.page-sidebar';
|
||||
const mainSelector = opts.mainSelector || '.page-main';
|
||||
const storageKey = opts.storageKey || '';
|
||||
const mobileBreakpoint = Number(opts.mobileBreakpoint || 900);
|
||||
const toggleLabel = String(opts.toggleLabel || t('sidebar.close'));
|
||||
const mobileDefaultOpen = !!opts.mobileDefaultOpen;
|
||||
|
||||
const sidebar = root.querySelector(sidebarSelector);
|
||||
const main = root.querySelector(mainSelector);
|
||||
if (!sidebar || !main) return () => { };
|
||||
|
||||
root.classList.add('page-with-sidebar');
|
||||
sidebar.classList.add('page-sidebar');
|
||||
main.classList.add('page-main');
|
||||
|
||||
const media = window.matchMedia(`(max-width: ${mobileBreakpoint}px)`);
|
||||
let desktopHidden = false;
|
||||
let mobileOpen = false;
|
||||
|
||||
if (storageKey) {
|
||||
try {
|
||||
desktopHidden = localStorage.getItem(storageKey) === '1';
|
||||
} catch {
|
||||
desktopHidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
const btn = document.createElement('button');
|
||||
btn.type = 'button';
|
||||
btn.className = 'btn sidebar-toggle-btn sidebar-fab sidebar-fab-unified';
|
||||
btn.innerHTML = '<span aria-hidden="true">☰</span>';
|
||||
btn.title = toggleLabel;
|
||||
btn.setAttribute('aria-label', toggleLabel);
|
||||
|
||||
const backdrop = document.createElement('button');
|
||||
backdrop.type = 'button';
|
||||
backdrop.className = 'page-sidebar-backdrop';
|
||||
backdrop.setAttribute('aria-label', 'Close sidebar');
|
||||
|
||||
if (!root.querySelector(':scope > .sidebar-fab')) {
|
||||
root.appendChild(btn);
|
||||
}
|
||||
if (!root.querySelector(':scope > .page-sidebar-backdrop')) {
|
||||
root.appendChild(backdrop);
|
||||
}
|
||||
|
||||
function setDesktopHidden(next) {
|
||||
desktopHidden = !!next;
|
||||
root.classList.toggle('sidebar-collapsed', desktopHidden);
|
||||
if (storageKey) {
|
||||
try { localStorage.setItem(storageKey, desktopHidden ? '1' : '0'); } catch { }
|
||||
}
|
||||
refreshFabVisibility();
|
||||
}
|
||||
|
||||
function setMobileOpen(next) {
|
||||
mobileOpen = !!next;
|
||||
root.classList.toggle('sidebar-open', mobileOpen);
|
||||
refreshFabVisibility();
|
||||
}
|
||||
|
||||
function syncMode() {
|
||||
if (media.matches) {
|
||||
root.classList.add('sidebar-mobile');
|
||||
root.classList.remove('sidebar-collapsed');
|
||||
setMobileOpen(mobileDefaultOpen);
|
||||
} else {
|
||||
root.classList.remove('sidebar-mobile');
|
||||
setMobileOpen(false);
|
||||
setDesktopHidden(desktopHidden);
|
||||
}
|
||||
refreshFabVisibility();
|
||||
}
|
||||
|
||||
function refreshFabVisibility() {
|
||||
if (media.matches) {
|
||||
btn.style.display = mobileOpen ? 'none' : '';
|
||||
return;
|
||||
}
|
||||
btn.style.display = desktopHidden ? '' : 'none';
|
||||
}
|
||||
|
||||
function onToggle() {
|
||||
if (media.matches) {
|
||||
setMobileOpen(!mobileOpen);
|
||||
} else {
|
||||
setDesktopHidden(!desktopHidden);
|
||||
}
|
||||
}
|
||||
|
||||
function onHideBtn() {
|
||||
if (media.matches) setMobileOpen(false);
|
||||
else setDesktopHidden(true);
|
||||
}
|
||||
|
||||
function onBackdrop() {
|
||||
if (media.matches) setMobileOpen(false);
|
||||
}
|
||||
|
||||
btn.addEventListener('click', onToggle);
|
||||
backdrop.addEventListener('click', onBackdrop);
|
||||
media.addEventListener('change', syncMode);
|
||||
|
||||
const hideBtn = sidebar.querySelector('#hideSidebar, [data-hide-sidebar="1"]');
|
||||
if (hideBtn) hideBtn.addEventListener('click', onHideBtn);
|
||||
|
||||
syncMode();
|
||||
refreshFabVisibility();
|
||||
|
||||
return () => {
|
||||
btn.removeEventListener('click', onToggle);
|
||||
backdrop.removeEventListener('click', onBackdrop);
|
||||
media.removeEventListener('change', syncMode);
|
||||
if (hideBtn) hideBtn.removeEventListener('click', onHideBtn);
|
||||
if (btn.parentNode) btn.parentNode.removeChild(btn);
|
||||
if (backdrop.parentNode) backdrop.parentNode.removeChild(backdrop);
|
||||
root.classList.remove('sidebar-open', 'sidebar-collapsed', 'sidebar-mobile', 'page-with-sidebar');
|
||||
sidebar.classList.remove('page-sidebar');
|
||||
main.classList.remove('page-main');
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user