You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
3.2 KiB
JavaScript

class Sidebar {
constructor(onSelectSurface) {
this.onSelectSurface = onSelectSurface;
this.sidebar = document.getElementById('sidebar');
this.overlay = document.getElementById('sidebar-overlay');
this.tree = document.getElementById('sidebar-tree');
this.menuBtn = document.getElementById('menu-btn');
this.closeBtn = document.getElementById('sidebar-close');
this.workspaces = [];
this.activeSurface = null;
this._loaded = false;
this.menuBtn.addEventListener('click', () => this.open());
this.closeBtn.addEventListener('click', () => this.close());
this.overlay.addEventListener('click', () => this.close());
// On desktop, sidebar is always visible via CSS (position: relative)
// Check on resize to close overlay if switching to desktop
this._onResize = () => {
if (window.innerWidth >= 1024) {
this.overlay.classList.remove('visible');
}
};
window.addEventListener('resize', this._onResize);
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && this.isOpen() && !this.isDesktop()) this.close();
});
this.render();
}
open() {
this.sidebar.classList.add('open');
this.overlay.classList.add('visible');
}
close() {
this.sidebar.classList.remove('open');
this.overlay.classList.remove('visible');
}
isDesktop() {
return window.innerWidth >= 1024;
}
isOpen() {
return this.sidebar.classList.contains('open');
}
setWorkspaces(workspaces) {
this.workspaces = workspaces;
this._loaded = true;
this.render();
}
setActiveSurface(surfaceRef) {
this.activeSurface = surfaceRef;
this.render();
}
render() {
this.tree.innerHTML = '';
if (this.workspaces.length === 0) {
const empty = document.createElement('div');
empty.className = 'sidebar-empty';
empty.textContent = this._loaded ? 'No workspaces' : 'Loading...';
this.tree.appendChild(empty);
return;
}
for (const ws of this.workspaces) {
// Workspace group label
const groupLabel = document.createElement('div');
groupLabel.className = 'ws-group-label';
groupLabel.textContent = ws.name || ws.ref;
this.tree.appendChild(groupLabel);
// Surfaces within workspace
for (const pane of ws.panes) {
for (const surface of pane.surfaces) {
const item = document.createElement('div');
item.className = 'surface-item';
if (surface.ref === this.activeSurface) {
item.classList.add('active');
}
const icon = document.createElement('span');
icon.className = 'surface-icon';
icon.textContent = surface.type === 'browser' ? '\u{1F310}' : '\u{1F4BB}';
const label = document.createElement('span');
label.className = 'ws-label';
label.textContent = surface.title || surface.ref;
item.appendChild(icon);
item.appendChild(label);
item.addEventListener('click', () => {
this.onSelectSurface(ws.ref, surface.ref);
this.setActiveSurface(surface.ref);
if (!this.isDesktop()) this.close();
});
this.tree.appendChild(item);
}
}
}
}
}
window.Sidebar = Sidebar;