mirror of
https://github.com/infinition/Bjorn.git
synced 2026-03-10 06:31:59 +00:00
- 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.
132 lines
3.9 KiB
JavaScript
132 lines
3.9 KiB
JavaScript
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');
|
|
};
|
|
}
|