Bundle frontend with esbuild, serve fonts offline, fix dashboard

- Add esbuild bundling: JS (IIFE, minified, sourcemapped) and CSS into
  single dist/ files, replacing 15+ individual CSS links and CDN scripts
- Bundle Chart.js and ELK.js from npm instead of CDN (fully offline)
- Serve DM Sans and Orbitron fonts locally from static/fonts/
- Fix dashboard automation card stretching full width (max-width: 500px)
- Fix time_of_day condition not localized in automation cards
- Add Chrome browser tools context file for MCP testing workflow
- Update frontend context with bundling docs and Chrome tools reference

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-14 22:20:20 +03:00
parent 46d77052ad
commit 49c2a63d68
16 changed files with 978 additions and 23 deletions

View File

@@ -0,0 +1,17 @@
/* CSS bundle entry — imports all stylesheets in correct order */
@import './fonts.css';
@import './base.css';
@import './layout.css';
@import './components.css';
@import './cards.css';
@import './modal.css';
@import './calibration.css';
@import './advanced-calibration.css';
@import './dashboard.css';
@import './streams.css';
@import './patterns.css';
@import './automations.css';
@import './tree-nav.css';
@import './tutorials.css';
@import './graph-editor.css';
@import './mobile.css';

View File

@@ -306,6 +306,10 @@
flex-shrink: 0;
}
.dashboard-automation {
max-width: 500px;
}
.dashboard-automation .dashboard-target-metrics {
min-width: 48px;
}

View File

@@ -0,0 +1,31 @@
/* Local font faces — no external CDN dependency */
/* DM Sans — latin-ext */
@font-face {
font-family: 'DM Sans';
font-style: normal;
font-weight: 400 700;
font-display: swap;
src: url('../fonts/dm-sans-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* DM Sans — latin */
@font-face {
font-family: 'DM Sans';
font-style: normal;
font-weight: 400 700;
font-display: swap;
src: url('../fonts/dm-sans-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Orbitron 700 — latin */
@font-face {
font-family: 'Orbitron';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('../fonts/orbitron-700-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

View File

@@ -2,7 +2,7 @@
* Graph layout via ELK.js — converts entity data into positioned nodes/edges.
*/
/* global ELK */
import ELK from 'elkjs/lib/elk.bundled.js';
const NODE_WIDTH = 190;
const NODE_HEIGHT = 56;

View File

@@ -681,7 +681,8 @@ function renderDashboardAutomation(automation, sceneMap = new Map()) {
return `${apps} (${matchLabel})`;
}
if (c.condition_type === 'startup') return t('automations.condition.startup');
return c.condition_type;
if (c.condition_type === 'time_of_day') return t('automations.condition.time_of_day');
return t(`automations.condition.${c.condition_type}`) || c.condition_type;
});
const logic = automation.condition_logic === 'and' ? ' & ' : ' | ';
condSummary = parts.join(logic);

View File

@@ -3,6 +3,10 @@
* History is seeded from the server-side ring buffer on init.
*/
import { Chart, registerables } from 'chart.js';
Chart.register(...registerables);
window.Chart = Chart; // expose globally for targets.js, dashboard.js
import { API_BASE, getHeaders } from '../core/api.js';
import { t } from '../core/i18n.js';
import { dashboardPollInterval } from '../core/state.js';