feat: TurboSu initial release - racing telemetry dashboard
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
const PageDashboard = {
|
||||
_el: null,
|
||||
_currentCategory: 'all',
|
||||
|
||||
init() {
|
||||
this._el = document.getElementById('page-dashboard');
|
||||
},
|
||||
|
||||
async render() {
|
||||
this._el.innerHTML = this._template();
|
||||
await this._loadCategories();
|
||||
await this._loadThemes();
|
||||
this._bindEvents();
|
||||
},
|
||||
|
||||
async _loadCategories() {
|
||||
try {
|
||||
const cats = await API.getCategories();
|
||||
const listEl = document.getElementById('dash-category-list');
|
||||
if (!listEl) return;
|
||||
|
||||
const allItem = document.createElement('div');
|
||||
allItem.className = 'category-item active';
|
||||
allItem.textContent = '全部';
|
||||
allItem.dataset.cat = 'all';
|
||||
listEl.appendChild(allItem);
|
||||
|
||||
cats.forEach(cat => {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'category-item';
|
||||
item.textContent = cat;
|
||||
item.dataset.cat = cat;
|
||||
listEl.appendChild(item);
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('Failed to load categories:', e);
|
||||
}
|
||||
},
|
||||
|
||||
async _loadThemes() {
|
||||
const gridEl = document.getElementById('dash-theme-grid');
|
||||
if (!gridEl) return;
|
||||
|
||||
gridEl.innerHTML = '<div style="text-align:center;padding:40px;color:var(--text-tertiary);">加载中...</div>';
|
||||
|
||||
try {
|
||||
const themes = await API.getDashboards(this._currentCategory);
|
||||
if (!themes || themes.length === 0) {
|
||||
gridEl.innerHTML = `
|
||||
<div class="empty-state" style="grid-column:1/-1;">
|
||||
<svg viewBox="0 0 24 24" width="64" height="64"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-12c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4z" fill="currentColor"/></svg>
|
||||
<h4>暂无仪表盘主题</h4>
|
||||
<p>创建或导入你的第一个仪表盘主题</p>
|
||||
</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
gridEl.innerHTML = themes.map(t => this._themeCardHtml(t)).join('');
|
||||
} catch (e) {
|
||||
console.error('Failed to load themes:', e);
|
||||
gridEl.innerHTML = '<div style="text-align:center;padding:40px;color:var(--danger);">加载失败</div>';
|
||||
}
|
||||
},
|
||||
|
||||
_bindEvents() {
|
||||
const categoryList = document.getElementById('dash-category-list');
|
||||
if (categoryList) {
|
||||
categoryList.addEventListener('click', (e) => {
|
||||
const item = e.target.closest('.category-item');
|
||||
if (!item) return;
|
||||
categoryList.querySelectorAll('.category-item').forEach(el => el.classList.remove('active'));
|
||||
item.classList.add('active');
|
||||
this._currentCategory = item.dataset.cat;
|
||||
this._loadThemes();
|
||||
});
|
||||
}
|
||||
|
||||
const gridEl = document.getElementById('dash-theme-grid');
|
||||
if (gridEl) {
|
||||
gridEl.addEventListener('click', (e) => {
|
||||
const card = e.target.closest('.theme-card');
|
||||
if (!card) return;
|
||||
const themeId = card.dataset.themeId;
|
||||
this._openDashboard(themeId);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_openDashboard(themeId) {
|
||||
const url = `${location.origin}/dashboard/${themeId}`;
|
||||
window.open(url, '_blank');
|
||||
navigator.clipboard.writeText(url).then(() => {
|
||||
Toast.show('链接已复制,可在局域网设备访问', 'success');
|
||||
}).catch(() => {
|
||||
Toast.show(`打开地址: ${url}`, 'info');
|
||||
});
|
||||
},
|
||||
|
||||
_themeCardHtml(theme) {
|
||||
const icon = theme.config?.icon || '📊';
|
||||
const aspect = theme.config?.aspect_ratio || 'auto';
|
||||
return `
|
||||
<div class="glass-card theme-card" data-theme-id="${theme.id}">
|
||||
<div class="theme-card-preview">${icon}</div>
|
||||
<div class="theme-card-info">
|
||||
<div class="theme-card-name">${theme.name || 'Unnamed'}</div>
|
||||
<div class="theme-card-meta">
|
||||
<span>${theme.category || 'basic'}</span>
|
||||
<span>${aspect}</span>
|
||||
</div>
|
||||
<div class="theme-card-meta" style="margin-top:4px;">
|
||||
<span>${theme.author || ''}</span>
|
||||
<span class="badge ${theme.is_builtin ? 'badge-info' : 'badge-success'}">${theme.is_builtin ? '内置' : '自定义'}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
},
|
||||
|
||||
_template() {
|
||||
return `
|
||||
<div class="dashboard-layout">
|
||||
<div class="dashboard-sub-sidebar">
|
||||
<div id="dash-category-list"></div>
|
||||
</div>
|
||||
<div class="dashboard-main">
|
||||
<div id="dash-theme-grid" class="theme-grid"></div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
};
|
||||
|
||||
window.PageDashboard = PageDashboard;
|
||||
Reference in New Issue
Block a user