Light theme
This commit is contained in:
146
web-config.html
146
web-config.html
@@ -20,14 +20,98 @@
|
||||
--label: #5a6480;
|
||||
--mono: 'Share Tech Mono', monospace;
|
||||
--sans: 'Barlow Condensed', sans-serif;
|
||||
--logo-color: #ffffff;
|
||||
/* Component tokens */
|
||||
--header-bg: rgba(10,12,14,0.96);
|
||||
--scanline: rgba(0,0,0,0.07);
|
||||
--hover-desc-color: rgba(10,12,14,0.65);
|
||||
/* Canvas */
|
||||
--canvas-bg: #0d1013;
|
||||
--canvas-fade: rgba(13,16,19,0.25);
|
||||
--canvas-grid: rgba(31,36,40,0.6);
|
||||
--canvas-center: rgba(58,64,80,0.5);
|
||||
--canvas-idle-text: rgba(90,100,128,0.7);
|
||||
--trail-rgb: 0,229,255;
|
||||
--trail-idle-rgb: 58,64,80;
|
||||
--canvas-dot: #00e5ff;
|
||||
--canvas-dot-idle: #3a4050;
|
||||
--canvas-dot-glow: rgba(0,229,255,0.35);
|
||||
/* Tap flashes */
|
||||
--tap-left: rgba(0,229,255,0.35);
|
||||
--tap-right: rgba(255,61,113,0.35);
|
||||
}
|
||||
|
||||
/* ── Light theme (explicit) ──────────────────────────────────────────────── */
|
||||
:root.theme-light {
|
||||
--bg: #f0f2f5;
|
||||
--panel: #ffffff;
|
||||
--panel2: #e8eaed;
|
||||
--border: #b8bec8;
|
||||
--accent: #006699;
|
||||
--accent2: #c01a50;
|
||||
--warn: #b36a00;
|
||||
--ok: #007040;
|
||||
--dim: #848ea4;
|
||||
--text: #0f1118;
|
||||
--label: #4e566e;
|
||||
--logo-color: #0f1118;
|
||||
--header-bg: rgba(240,242,245,0.96);
|
||||
--scanline: rgba(0,0,0,0.03);
|
||||
--hover-desc-color: rgba(240,242,245,0.7);
|
||||
--canvas-bg: #e8eaed;
|
||||
--canvas-fade: rgba(232,234,237,0.35);
|
||||
--canvas-grid: rgba(195,200,210,0.7);
|
||||
--canvas-center: rgba(155,162,178,0.6);
|
||||
--canvas-idle-text: rgba(100,112,140,0.8);
|
||||
--trail-rgb: 0,100,170;
|
||||
--trail-idle-rgb: 155,162,178;
|
||||
--canvas-dot: #0077aa;
|
||||
--canvas-dot-idle: #a8b0c0;
|
||||
--canvas-dot-glow: rgba(0,100,170,0.3);
|
||||
--tap-left: rgba(0,100,170,0.35);
|
||||
--tap-right: rgba(200,30,80,0.35);
|
||||
}
|
||||
|
||||
/* ── Auto light (OS hint; explicit class overrides) ──────────────────────── */
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root:not(.theme-dark) {
|
||||
--bg: #f0f2f5;
|
||||
--panel: #ffffff;
|
||||
--panel2: #e8eaed;
|
||||
--border: #b8bec8;
|
||||
--accent: #006699;
|
||||
--accent2: #c01a50;
|
||||
--warn: #b36a00;
|
||||
--ok: #007040;
|
||||
--dim: #848ea4;
|
||||
--text: #0f1118;
|
||||
--label: #4e566e;
|
||||
--logo-color: #0f1118;
|
||||
--header-bg: rgba(240,242,245,0.96);
|
||||
--scanline: rgba(0,0,0,0.03);
|
||||
--hover-desc-color: rgba(240,242,245,0.7);
|
||||
--canvas-bg: #e8eaed;
|
||||
--canvas-fade: rgba(232,234,237,0.35);
|
||||
--canvas-grid: rgba(195,200,210,0.7);
|
||||
--canvas-center: rgba(155,162,178,0.6);
|
||||
--canvas-idle-text: rgba(100,112,140,0.8);
|
||||
--trail-rgb: 0,100,170;
|
||||
--trail-idle-rgb: 155,162,178;
|
||||
--canvas-dot: #0077aa;
|
||||
--canvas-dot-idle: #a8b0c0;
|
||||
--canvas-dot-glow: rgba(0,100,170,0.3);
|
||||
--tap-left: rgba(0,100,170,0.35);
|
||||
--tap-right: rgba(200,30,80,0.35);
|
||||
}
|
||||
}
|
||||
|
||||
* { box-sizing:border-box; margin:0; padding:0; }
|
||||
body { background:var(--bg); color:var(--text); font-family:var(--mono); min-height:100vh; overflow-x:hidden; }
|
||||
body::before { content:''; position:fixed; inset:0; pointer-events:none; z-index:9999;
|
||||
background:repeating-linear-gradient(0deg,transparent,transparent 2px,rgba(0,0,0,0.07) 2px,rgba(0,0,0,0.07) 4px); }
|
||||
background:repeating-linear-gradient(0deg,transparent,transparent 2px,var(--scanline) 2px,var(--scanline) 4px); }
|
||||
|
||||
header { border-bottom:1px solid var(--border); padding:16px 28px; display:flex; align-items:center; gap:20px; position:sticky; top:0; background:rgba(10,12,14,0.96); backdrop-filter:blur(10px); z-index:100; }
|
||||
.logo { font-family:var(--sans); font-weight:900; font-size:22px; letter-spacing:0.08em; color:#fff; text-transform:uppercase; line-height:1; }
|
||||
header { border-bottom:1px solid var(--border); padding:16px 28px; display:flex; align-items:center; gap:20px; position:sticky; top:0; background:var(--header-bg); backdrop-filter:blur(10px); z-index:100; }
|
||||
.logo { font-family:var(--sans); font-weight:900; font-size:22px; letter-spacing:0.08em; color:var(--logo-color); text-transform:uppercase; line-height:1; }
|
||||
.logo span { color:var(--accent); }
|
||||
.logo-sub { font-size:10px; color:var(--label); letter-spacing:0.25em; text-transform:uppercase; margin-top:3px; }
|
||||
.header-right { margin-left:auto; display:flex; align-items:center; gap:10px; flex-wrap:wrap; justify-content:flex-end; }
|
||||
@@ -53,6 +137,8 @@
|
||||
.btn:disabled { border-color:var(--dim); color:var(--dim); cursor:not-allowed; }
|
||||
.btn:disabled::before { display:none; }
|
||||
.btn:disabled:hover { color:var(--dim); }
|
||||
.btn-theme { border:1px solid var(--dim); color:var(--label); min-width:72px; text-align:center; }
|
||||
.btn-theme::before { background:var(--text); }
|
||||
|
||||
.batt-bar { display:flex; align-items:center; gap:8px; font-size:11px; color:var(--label); }
|
||||
.batt-cells { display:flex; gap:2px; }
|
||||
@@ -117,7 +203,7 @@
|
||||
.cmd-btn::before { content:''; position:absolute; inset:0; opacity:0; transition:opacity 0.2s; }
|
||||
.cmd-btn:hover::before { opacity:1; }
|
||||
.cmd-btn:hover { color:var(--bg); }
|
||||
.cmd-btn:hover .cmd-desc { color:rgba(10,12,14,0.65); }
|
||||
.cmd-btn:hover .cmd-desc { color:var(--hover-desc-color); }
|
||||
.cmd-btn.calibrate::before { background:var(--accent); }
|
||||
.cmd-btn.calibrate:hover { border-color:var(--accent); }
|
||||
.cmd-btn.reset::before { background:var(--accent2); }
|
||||
@@ -187,8 +273,8 @@
|
||||
body.disconnected .cmd-grid { opacity:0.45; pointer-events:none; transition:opacity 0.3s; }
|
||||
|
||||
.tap-flash { position:absolute; inset:0; pointer-events:none; opacity:0; transition:opacity 0.25s; }
|
||||
.tap-flash.left { background:radial-gradient(circle at center, rgba(0,229,255,0.35) 0%, transparent 70%); }
|
||||
.tap-flash.right { background:radial-gradient(circle at center, rgba(255,61,113,0.35) 0%, transparent 70%); }
|
||||
.tap-flash.left { background:radial-gradient(circle at center, var(--tap-left) 0%, transparent 70%); }
|
||||
.tap-flash.right { background:radial-gradient(circle at center, var(--tap-right) 0%, transparent 70%); }
|
||||
.tap-flash.show { opacity:1; }
|
||||
.viz-wrap { position:relative; }
|
||||
</style>
|
||||
@@ -207,6 +293,7 @@
|
||||
<div class="batt-cells" id="battCells"></div>
|
||||
<span id="battPct">--%</span>
|
||||
</div>
|
||||
<button class="btn btn-theme" id="themeBtn" onclick="cycleTheme()"><span>AUTO</span></button>
|
||||
<div class="status-pill" id="statusPill"><div class="dot"></div><span id="statusText">DISCONNECTED</span></div>
|
||||
<button class="btn btn-connect" id="connectBtn" onclick="doConnect()"><span>Connect</span></button>
|
||||
<button class="btn btn-disconnect" id="disconnectBtn" onclick="doDisconnect()" style="display:none"><span>Disconnect</span></button>
|
||||
@@ -382,6 +469,7 @@ function log(msg, type='') {
|
||||
el.appendChild(d); el.scrollTop=el.scrollHeight;
|
||||
}
|
||||
const p2=n=>String(n).padStart(2,'0'), p3=n=>String(n).padStart(3,'0');
|
||||
function cssVar(n) { return getComputedStyle(document.documentElement).getPropertyValue(n).trim(); }
|
||||
|
||||
// ── Connection ───────────────────────────────────────────────────────────────
|
||||
async function doConnect() {
|
||||
@@ -712,26 +800,28 @@ function updateAxisBar(axis, val, max) {
|
||||
|
||||
function drawViz(idle) {
|
||||
const W=canvas.width, H=canvas.height;
|
||||
ctx.fillStyle='rgba(13,16,19,0.25)'; ctx.fillRect(0,0,W,H);
|
||||
ctx.strokeStyle='rgba(31,36,40,0.6)'; ctx.lineWidth=0.5;
|
||||
ctx.fillStyle=cssVar('--canvas-fade'); ctx.fillRect(0,0,W,H);
|
||||
ctx.strokeStyle=cssVar('--canvas-grid'); ctx.lineWidth=0.5;
|
||||
for(let x=0;x<W;x+=40){ctx.beginPath();ctx.moveTo(x,0);ctx.lineTo(x,H);ctx.stroke();}
|
||||
for(let y=0;y<H;y+=40){ctx.beginPath();ctx.moveTo(0,y);ctx.lineTo(W,y);ctx.stroke();}
|
||||
ctx.strokeStyle='rgba(58,64,80,0.5)'; ctx.lineWidth=0.5;
|
||||
ctx.strokeStyle=cssVar('--canvas-center'); ctx.lineWidth=0.5;
|
||||
ctx.beginPath();ctx.moveTo(W/2,0);ctx.lineTo(W/2,H);ctx.stroke();
|
||||
ctx.beginPath();ctx.moveTo(0,H/2);ctx.lineTo(W,H/2);ctx.stroke();
|
||||
const now=Date.now();
|
||||
const trailRgb=cssVar('--trail-rgb'), trailIdleRgb=cssVar('--trail-idle-rgb');
|
||||
for(let i=1;i<trail.length;i++){
|
||||
const age=(now-trail[i].t)/1200, alpha=Math.max(0,1-age); if(alpha<=0) continue;
|
||||
ctx.strokeStyle=trail[i].idle?`rgba(58,64,80,${alpha*0.4})`:`rgba(0,229,255,${alpha*0.7})`;
|
||||
ctx.strokeStyle=trail[i].idle?`rgba(${trailIdleRgb},${alpha*0.4})`:`rgba(${trailRgb},${alpha*0.7})`;
|
||||
ctx.lineWidth=1.5;
|
||||
ctx.beginPath();ctx.moveTo(trail[i-1].x,trail[i-1].y);ctx.lineTo(trail[i].x,trail[i].y);ctx.stroke();
|
||||
}
|
||||
const dotColor=idle?'#3a4050':'#00e5ff', dotGlow=idle?'transparent':'rgba(0,229,255,0.35)';
|
||||
const dotColor=idle?cssVar('--canvas-dot-idle'):cssVar('--canvas-dot');
|
||||
const dotGlow=idle?'transparent':cssVar('--canvas-dot-glow');
|
||||
ctx.shadowColor=dotGlow; ctx.shadowBlur=12;
|
||||
ctx.fillStyle=dotColor;
|
||||
ctx.beginPath();ctx.arc(cursorX,cursorY,idle?3:5,0,Math.PI*2);ctx.fill();
|
||||
ctx.shadowBlur=0;
|
||||
if(idle){ctx.fillStyle='rgba(90,100,128,0.7)';ctx.font='10px Share Tech Mono,monospace';ctx.textAlign='center';ctx.fillText('IDLE',W/2,H-10);ctx.textAlign='left';}
|
||||
if(idle){ctx.fillStyle=cssVar('--canvas-idle-text');ctx.font='10px Share Tech Mono,monospace';ctx.textAlign='center';ctx.fillText('IDLE',W/2,H-10);ctx.textAlign='left';}
|
||||
}
|
||||
|
||||
function flashTap(side){
|
||||
@@ -739,17 +829,39 @@ function flashTap(side){
|
||||
el.classList.add('show'); setTimeout(()=>el.classList.remove('show'),300);
|
||||
}
|
||||
|
||||
(function initCanvas(){
|
||||
function drawInitState() {
|
||||
const W=canvas.width,H=canvas.height;
|
||||
ctx.fillStyle='#0d1013';ctx.fillRect(0,0,W,H);
|
||||
ctx.strokeStyle='rgba(31,36,40,0.5)';ctx.lineWidth=0.5;
|
||||
ctx.fillStyle=cssVar('--canvas-bg');ctx.fillRect(0,0,W,H);
|
||||
ctx.strokeStyle=cssVar('--canvas-grid');ctx.lineWidth=0.5;
|
||||
for(let x=0;x<W;x+=40){ctx.beginPath();ctx.moveTo(x,0);ctx.lineTo(x,H);ctx.stroke();}
|
||||
for(let y=0;y<H;y+=40){ctx.beginPath();ctx.moveTo(0,y);ctx.lineTo(W,y);ctx.stroke();}
|
||||
ctx.strokeStyle='rgba(58,64,80,0.4)';
|
||||
ctx.strokeStyle=cssVar('--canvas-center');
|
||||
ctx.beginPath();ctx.moveTo(W/2,0);ctx.lineTo(W/2,H);ctx.stroke();
|
||||
ctx.beginPath();ctx.moveTo(0,H/2);ctx.lineTo(W,H/2);ctx.stroke();
|
||||
ctx.fillStyle='rgba(58,64,80,0.6)';ctx.font='10px Share Tech Mono,monospace';
|
||||
ctx.fillStyle=cssVar('--canvas-idle-text');ctx.font='10px Share Tech Mono,monospace';
|
||||
ctx.textAlign='center';ctx.fillText('connect to activate stream',W/2,H/2+4);ctx.textAlign='left';
|
||||
}
|
||||
// ── Theme ─────────────────────────────────────────────────────────────────────
|
||||
const THEMES = ['auto','dark','light'];
|
||||
const THEME_LABELS = {auto:'AUTO',dark:'DARK',light:'LIGHT'};
|
||||
let themeIdx = 0;
|
||||
|
||||
function cycleTheme() {
|
||||
themeIdx = (themeIdx + 1) % 3;
|
||||
applyTheme(THEMES[themeIdx]);
|
||||
}
|
||||
function applyTheme(t) {
|
||||
document.documentElement.classList.remove('theme-dark','theme-light');
|
||||
if (t === 'dark') document.documentElement.classList.add('theme-dark');
|
||||
if (t === 'light') document.documentElement.classList.add('theme-light');
|
||||
document.getElementById('themeBtn').querySelector('span').textContent = THEME_LABELS[t];
|
||||
localStorage.setItem('theme', t);
|
||||
if (!chars.imuStream) drawInitState();
|
||||
}
|
||||
(function(){
|
||||
const saved = localStorage.getItem('theme') ?? 'auto';
|
||||
themeIdx = Math.max(0, THEMES.indexOf(saved));
|
||||
applyTheme(saved);
|
||||
})();
|
||||
|
||||
if (!navigator.bluetooth) {
|
||||
|
||||
Reference in New Issue
Block a user