feat: dashboard manifest supports 'supported_games' field, frontend filters by selected game
- DashboardTheme model adds supported_games (default: 'all') - Built-in dashboards declare game compatibility: speedometer/tachometer/gear_indicator -> all lap_timer -> forza_horizon_5,forza_horizon_4,forza_motorsport,f1_24 - Dashboard browser filters themes by selected game - Card shows '全' (all) or '限' (limited) badge - Updated DASHBOARD_DEV.md with supported_games spec
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
const PageDashboard = {
|
||||
_el: null,
|
||||
_currentCategory: 'all',
|
||||
_selectedGameId: null,
|
||||
|
||||
init() {
|
||||
this._el = document.getElementById('page-dashboard');
|
||||
},
|
||||
|
||||
async render() {
|
||||
const cfg = await API.getConfig();
|
||||
this._selectedGameId = cfg.selected_game_id;
|
||||
this._el.innerHTML = this._template();
|
||||
await this._loadCategories();
|
||||
await this._loadThemes();
|
||||
@@ -44,14 +47,18 @@ const PageDashboard = {
|
||||
gridEl.innerHTML = '<div style="text-align:center;padding:40px;color:var(--text-tertiary);">加载中...</div>';
|
||||
|
||||
try {
|
||||
const themes = await API.getDashboards(this._currentCategory);
|
||||
let 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>`;
|
||||
gridEl.innerHTML = this._emptyHtml();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._selectedGameId) {
|
||||
themes = themes.filter(t => this._isGameSupported(t));
|
||||
}
|
||||
|
||||
if (themes.length === 0) {
|
||||
gridEl.innerHTML = this._emptyHtml('当前游戏没有兼容的仪表盘');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -62,6 +69,22 @@ const PageDashboard = {
|
||||
}
|
||||
},
|
||||
|
||||
_isGameSupported(theme) {
|
||||
const supported = theme.supported_games || 'all';
|
||||
if (supported === 'all') return true;
|
||||
const ids = supported.split(',').map(s => s.trim());
|
||||
return ids.includes(this._selectedGameId);
|
||||
},
|
||||
|
||||
_emptyHtml(msg) {
|
||||
return `
|
||||
<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>${msg || '暂无仪表盘主题'}</h4>
|
||||
<p>创建或导入你的仪表盘主题</p>
|
||||
</div>`;
|
||||
},
|
||||
|
||||
_bindEvents() {
|
||||
const categoryList = document.getElementById('dash-category-list');
|
||||
if (categoryList) {
|
||||
@@ -133,6 +156,10 @@ const PageDashboard = {
|
||||
_themeCardHtml(theme) {
|
||||
const icon = theme.icon || '📊';
|
||||
const aspect = theme.aspect_ratio || 'auto';
|
||||
const supported = theme.supported_games || 'all';
|
||||
const isAll = supported === 'all';
|
||||
const compatLabel = isAll ? '全' : '限';
|
||||
const compatClass = isAll ? 'badge-info' : 'badge-warning';
|
||||
return `
|
||||
<div class="glass-card theme-card" data-theme-id="${theme.id}">
|
||||
<div class="theme-card-preview">${icon}</div>
|
||||
@@ -144,7 +171,7 @@ const PageDashboard = {
|
||||
</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>
|
||||
<span class="badge ${compatClass}">${compatLabel}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
Reference in New Issue
Block a user