128 lines
4.6 KiB
JavaScript
128 lines
4.6 KiB
JavaScript
const Sidebar = {
|
|
_el: null,
|
|
_gameListEl: null,
|
|
_gameToggleEl: null,
|
|
_gameLabelEl: null,
|
|
_gameData: [],
|
|
|
|
init() {
|
|
this._el = document.getElementById('sidebar');
|
|
this._gameListEl = document.getElementById('game-list');
|
|
this._gameToggleEl = document.getElementById('game-selector-toggle');
|
|
this._gameLabelEl = document.getElementById('game-selector-label');
|
|
this._topbarLogo = document.getElementById('topbar-logo-title');
|
|
|
|
document.getElementById('sidebar-toggle').addEventListener('click', () => this.toggle());
|
|
this._gameToggleEl.addEventListener('click', () => this._toggleGameList());
|
|
|
|
const saved = localStorage.getItem('turbosu-sidebar-collapsed');
|
|
if (saved === 'true') this.collapse(true);
|
|
|
|
this._loadGames();
|
|
},
|
|
|
|
toggle() {
|
|
this._el.classList.toggle('collapsed');
|
|
this._el.classList.toggle('expanded');
|
|
const isCollapsed = this._el.classList.contains('collapsed');
|
|
this._topbarLogo.classList.toggle('hidden', !isCollapsed);
|
|
localStorage.setItem('turbosu-sidebar-collapsed', isCollapsed);
|
|
},
|
|
|
|
collapse(silent) {
|
|
this._el.classList.add('collapsed');
|
|
this._el.classList.remove('expanded');
|
|
this._topbarLogo.classList.remove('hidden');
|
|
if (!silent) localStorage.setItem('turbosu-sidebar-collapsed', 'true');
|
|
},
|
|
|
|
expand(silent) {
|
|
this._el.classList.remove('collapsed');
|
|
this._el.classList.add('expanded');
|
|
this._topbarLogo.classList.add('hidden');
|
|
if (!silent) localStorage.setItem('turbosu-sidebar-collapsed', 'false');
|
|
},
|
|
|
|
async _loadGames() {
|
|
const games = await API.getGames();
|
|
this._gameData = games;
|
|
this._gameListEl.innerHTML = '';
|
|
|
|
if (!Array.isArray(games) || games.length === 0) {
|
|
this._gameListEl.innerHTML = '<div style="padding:8px 12px;color:var(--text-tertiary);font-size:12px;">' + Lang.t('noGamePlugins') + '</div>';
|
|
return;
|
|
}
|
|
|
|
const selectedId = (await API.getConfig()).selected_game_id;
|
|
games.forEach(game => {
|
|
const item = document.createElement('button');
|
|
item.className = 'nav-item';
|
|
if (selectedId === game.id) item.classList.add('active');
|
|
item.innerHTML = `
|
|
<span style="font-size:16px;flex-shrink:0;">◉</span>
|
|
<span class="nav-label">${game.name}</span>
|
|
`;
|
|
item.addEventListener('click', () => this._selectGame(game.id));
|
|
this._gameListEl.appendChild(item);
|
|
});
|
|
|
|
this._updateGameLabel(selectedId, games);
|
|
},
|
|
|
|
_updateGameLabel(selectedId, games) {
|
|
if (selectedId && games) {
|
|
const game = games.find(g => g.id === selectedId);
|
|
if (game) {
|
|
this._gameLabelEl.textContent = game.name;
|
|
return;
|
|
}
|
|
}
|
|
this._gameLabelEl.textContent = Lang.t('selectGame');
|
|
},
|
|
|
|
async _selectGame(gameId) {
|
|
await API.updateConfig({ selected_game_id: gameId });
|
|
const cfg = await API.getConfig();
|
|
if (!cfg.use_unified_port) {
|
|
const gamePort = (cfg.game_ports || {})[gameId] || this._gameData.find(g => g.id === gameId)?.default_port || 20777;
|
|
await API.updateConfig({ telemetry_port: gamePort });
|
|
}
|
|
await API.stopTelemetry();
|
|
await API.startTelemetry();
|
|
this._gameListEl.querySelectorAll('.nav-item').forEach(el => el.classList.remove('active'));
|
|
const items = this._gameListEl.querySelectorAll('.nav-item');
|
|
items.forEach((item, idx) => {
|
|
if (this._gameData[idx] && this._gameData[idx].id === gameId) item.classList.add('active');
|
|
});
|
|
const games = await API.getGames();
|
|
this._updateGameLabel(gameId, games);
|
|
this._loadGames();
|
|
|
|
if (typeof Router !== 'undefined' && Router.currentPage === 'scene') {
|
|
Router.navigate('scene');
|
|
}
|
|
},
|
|
|
|
_toggleGameList() {
|
|
const toggle = this._gameToggleEl;
|
|
const list = this._gameListEl;
|
|
const isCollapsed = toggle.classList.contains('collapsed');
|
|
|
|
if (isCollapsed) {
|
|
toggle.classList.remove('collapsed');
|
|
list.classList.remove('collapsed');
|
|
} else {
|
|
toggle.classList.add('collapsed');
|
|
list.classList.add('collapsed');
|
|
}
|
|
},
|
|
|
|
setActive(route) {
|
|
this._el.querySelectorAll('.nav-item[data-route]').forEach(el => {
|
|
el.classList.toggle('active', el.getAttribute('data-route') === route);
|
|
});
|
|
}
|
|
};
|
|
|
|
window.Sidebar = Sidebar;
|