Skip to content

Commit c618191

Browse files
fhirschmannclaude
andcommitted
feat: serve all web-UI assets locally so the interface works offline
The management page pulled jQuery, jQuery-UI, Bootstrap (JS+CSS), jstree (+themes), bootstrap-slider, Font Awesome and the Google fonts from public CDNs. With no/slow internet (every cold boot, AP mode) the browser hung for ~2 minutes on those requests and showed an untranslated, empty page (i18next itself came from a CDN, so no text appeared). All of these are now vendored under html/ and served gzipped straight from flash via the existing WWWData route mechanism, exactly like the locale files already were. management.html references only local /js, /css, /fonts, /webfonts and /jstree paths now; accesspoint.html was already CDN-free. Google fonts (Orbitron/Rajdhani/Share Tech Mono) are self-hosted as woff2 (latin + latin-ext) with a local @font-face stylesheet. processHtml.py changes: - read truly-binary assets (woff2/png/gif) as raw bytes instead of utf-8 (the old code would have crashed on them), - emit font/woff2 and image/svg+xml MIME types, - derive header symbol names from the full asset path so files that share a basename stem across dirs/extensions (bootstrap.*, the two themes' style.min.css / 32px.png) no longer collide. Web.cpp: the two direct symbol references updated to the new naming (management_html_BIN / accesspoint_html_BIN). Flash usage grows from ~45% to ~56% of the app partition. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 07877f7 commit c618191

36 files changed

Lines changed: 407 additions & 31 deletions

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ neon logo that doubles as the SVG favicon ([`7be5254`](../../commit/7be5254)):
133133
| Battery-backed **RTC** (DS3231): optional `RTC_ENABLE` adds a real-time clock on the external I²C bus so the time stays correct without WiFi/NTP. The RTC stores UTC and seeds the system clock at boot (before WiFi is up); NTP remains the master and disciplines the RTC on every sync and hourly. Current time (and DS3231 die-temperature) shown in the info dialog, published via the MQTT state-topic `rtc` (+ Home Assistant discovery), and the RTC can be re-disciplined from system time via the bindable command **155** (button/RFID modifier) | [`bf90f66`](../../commit/bf90f66) |
134134
| **Status control-LEDs**: the optional control LEDs (`NUM_CONTROL_LEDS`, soldered to the end of the same NeoPixel data line — no extra GPIO) can now mirror a runtime state instead of just showing a static color. Each control LED gets a per-slot function in the LED settings — **Static** (legacy fixed color), **Key lock** (red while controls are locked), **Repeat mode** (green = track, blue = playlist, purple = both), **Bluetooth** (violet = waiting, blue = connected), **Battery level** (state of charge as a green→yellow→red gradient) or **Off**. A master switch mutes all control LEDs (e.g. at night), toggleable via the bindable command **121** (button/RFID modifier) and the MQTT command/state-topic `control_leds` (`ON`/`OFF`, + Home Assistant discovery switch) | [`5cef32d`](../../commit/5cef32d) |
135135
| **HTTP file sync**: pull audio files from a web server (e.g. nginx) onto the SD card. A new **Sync** settings sub-tab takes a manifest URL plus optional HTTP Basic Auth (user/password); the device fetches a JSON manifest (`{"files":[{"path","size"},…]}`) and downloads every listed file that is missing locally or differs in size, streaming each in small chunks straight to SD. Additive only (never deletes), runs in a background task, refuses to start while audio is playing, and shows live progress including the file currently being downloaded plus a stop button to cancel a running sync. The Sync tab documents the manifest format and an nginx setup inline | [`d5c24fe`](../../commit/d5c24fe) |
136+
| **Fully offline web interface**: all third-party libraries (jQuery, jQuery-UI, Bootstrap JS/CSS, jstree + themes, bootstrap-slider, Font Awesome + webfonts, i18next) and the Orbitron/Rajdhani/Share Tech Mono fonts are now vendored and served gzipped from the device instead of public CDNs. This fixes the ~2-minute first-load hang with empty (untranslated) text after a cold boot/flash, and makes the management UI work without any internet access (incl. AP mode). `processHtml.py` embeds the assets into flash (build size grows accordingly) and now derives unique header symbol names from the full asset path | [`COMMIT_HASH`](../../commit/COMMIT_HASH) |
136137

137138
#### Feature highlights
138139

html/css/all.min.css

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

html/css/bootstrap-slider.min.css

Lines changed: 43 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

html/css/bootstrap.min.css

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

html/fonts/fonts.css

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
@font-face {
2+
font-family: 'Orbitron';
3+
font-style: normal;
4+
font-weight: 500;
5+
font-display: swap;
6+
src: url(/fonts/orbitron-500-latin-yMJRMIlzdpvBhQQL_Qq7dy0.woff2) format('woff2');
7+
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;
8+
}
9+
@font-face {
10+
font-family: 'Orbitron';
11+
font-style: normal;
12+
font-weight: 700;
13+
font-display: swap;
14+
src: url(/fonts/orbitron-500-latin-yMJRMIlzdpvBhQQL_Qq7dy0.woff2) format('woff2');
15+
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;
16+
}
17+
@font-face {
18+
font-family: 'Orbitron';
19+
font-style: normal;
20+
font-weight: 900;
21+
font-display: swap;
22+
src: url(/fonts/orbitron-500-latin-yMJRMIlzdpvBhQQL_Qq7dy0.woff2) format('woff2');
23+
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;
24+
}
25+
@font-face {
26+
font-family: 'Rajdhani';
27+
font-style: normal;
28+
font-weight: 400;
29+
font-display: swap;
30+
src: url(/fonts/rajdhani-400-latin-ext-LDIxapCSOBg7S-QT7p4JM-aUWA.woff2) format('woff2');
31+
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;
32+
}
33+
@font-face {
34+
font-family: 'Rajdhani';
35+
font-style: normal;
36+
font-weight: 400;
37+
font-display: swap;
38+
src: url(/fonts/rajdhani-400-latin-LDIxapCSOBg7S-QT7p4HM-Y.woff2) format('woff2');
39+
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;
40+
}
41+
@font-face {
42+
font-family: 'Rajdhani';
43+
font-style: normal;
44+
font-weight: 500;
45+
font-display: swap;
46+
src: url(/fonts/rajdhani-500-latin-ext-LDI2apCSOBg7S-QT7pb0EPOleef2kg.woff2) format('woff2');
47+
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;
48+
}
49+
@font-face {
50+
font-family: 'Rajdhani';
51+
font-style: normal;
52+
font-weight: 500;
53+
font-display: swap;
54+
src: url(/fonts/rajdhani-500-latin-LDI2apCSOBg7S-QT7pb0EPOreec.woff2) format('woff2');
55+
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;
56+
}
57+
@font-face {
58+
font-family: 'Rajdhani';
59+
font-style: normal;
60+
font-weight: 600;
61+
font-display: swap;
62+
src: url(/fonts/rajdhani-600-latin-ext-LDI2apCSOBg7S-QT7pbYF_Oleef2kg.woff2) format('woff2');
63+
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;
64+
}
65+
@font-face {
66+
font-family: 'Rajdhani';
67+
font-style: normal;
68+
font-weight: 600;
69+
font-display: swap;
70+
src: url(/fonts/rajdhani-600-latin-LDI2apCSOBg7S-QT7pbYF_Oreec.woff2) format('woff2');
71+
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;
72+
}
73+
@font-face {
74+
font-family: 'Rajdhani';
75+
font-style: normal;
76+
font-weight: 700;
77+
font-display: swap;
78+
src: url(/fonts/rajdhani-700-latin-ext-LDI2apCSOBg7S-QT7pa8FvOleef2kg.woff2) format('woff2');
79+
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;
80+
}
81+
@font-face {
82+
font-family: 'Rajdhani';
83+
font-style: normal;
84+
font-weight: 700;
85+
font-display: swap;
86+
src: url(/fonts/rajdhani-700-latin-LDI2apCSOBg7S-QT7pa8FvOreec.woff2) format('woff2');
87+
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;
88+
}
89+
@font-face {
90+
font-family: 'Share Tech Mono';
91+
font-style: normal;
92+
font-weight: 400;
93+
font-display: swap;
94+
src: url(/fonts/sharetechmono-400-latin-J7aHnp1uDWRBEqV98dVQztYldFcLowEF.woff2) format('woff2');
95+
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;
96+
}
11.5 KB
Binary file not shown.
14.6 KB
Binary file not shown.
Binary file not shown.
14.7 KB
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)