Loading www/app.css +4 −0 Changes for www/app.css: 4 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -277,6 +277,10 @@ svg.spark { display: block; width: 100%; height: 28px; margin-top: 10px; } @media (max-width: 720px) { .dash-two { grid-template-columns: 1fr; } } .legend { display: flex; flex-wrap: wrap; gap: 4px 16px; font-size: .9em; color: var(--muted); margin-bottom: 6px; } .legend b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; } .swatch.s1, .chart-area.s1, .chart-dot.s1 { background: var(--series-1); fill: var(--series-1); } .swatch.s2, .chart-area.s2, .chart-dot.s2 { background: var(--series-2); fill: var(--series-2); } .chart-line.s1 { stroke: var(--series-1); } .chart-line.s2 { stroke: var(--series-2); } .swatch { display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin-right: .4em; vertical-align: -1px; } .chart-plot { position: relative; touch-action: pan-y; } .chart-svg { display: block; } Loading www/modules/dashboard.js +16 −9 Changes for www/modules/dashboard.js: 16 added lines, 9 removed lines. Original line number Diff line number Diff line Loading @@ -118,7 +118,7 @@ const svg = s('svg', {class: 'chart-svg', height: H, role: 'img'}); const tip = h('div', {class: 'chart-tip', hidden: true}); const legend = h('div', {class: 'legend'}, series.map(sr => h('span', {}, h('i', {class: 'swatch', style: `background: var(${sr.color})`}), sr.label, ' ', h('b', {class: 'legend-value'})))); h('span', {}, h('i', {class: 'swatch ' + sr.color}), sr.label, ' ', h('b', {class: 'legend-value'})))); const plot = h('div', {class: 'chart-plot'}, svg, tip); const el = h('div', {class: 'chart'}, legend, plot); let hover = null; // index under the pointer Loading Loading @@ -153,18 +153,18 @@ if (n >= 2) { for (const sr of series) { const d = hist[sr.key].map((v, i) => (i ? 'L' : 'M') + x(i).toFixed(1) + ' ' + y(v).toFixed(1)).join(''); kids.push(s('path', {d: d + `L${x(n - 1).toFixed(1)} ${y(0)}L${x(0).toFixed(1)} ${y(0)}Z`, class: 'chart-area', style: `fill: var(${sr.color})`})); kids.push(s('path', {d, class: 'chart-line', style: `stroke: var(${sr.color})`})); kids.push(s('path', {d: d + `L${x(n - 1).toFixed(1)} ${y(0)}L${x(0).toFixed(1)} ${y(0)}Z`, class: 'chart-area ' + sr.color})); kids.push(s('path', {d, class: 'chart-line ' + sr.color})); } } if (hover !== null && hover < n) { const xx = x(hover); kids.push(s('line', {x1: xx, x2: xx, y1: PAD.t, y2: PAD.t + ph, class: 'crosshair'})); for (const sr of series) kids.push(s('circle', {cx: xx, cy: y(hist[sr.key][hover]), r: 4, class: 'chart-dot', style: `fill: var(${sr.color})`})); kids.push(s('circle', {cx: xx, cy: y(hist[sr.key][hover]), r: 4, class: 'chart-dot ' + sr.color})); const ago = Math.round((hist.at[n - 1] - hist.at[hover]) / 1000); tip.replaceChildren(h('div', {class: 'muted'}, ago ? t('{0} ago', ago + ' s') : t('now')), series.map(sr => h('div', {}, h('i', {class: 'swatch', style: `background: var(${sr.color})`}), sr.label + ': ', ...series.map(sr => h('div', {}, h('i', {class: 'swatch ' + sr.color}), sr.label + ': ', h('b', {}, format(hist[sr.key][hover]))))); tip.hidden = false; const left = xx + 12 + tip.offsetWidth > W ? xx - 12 - tip.offsetWidth : xx + 12; Loading Loading @@ -217,8 +217,8 @@ ui.disk = card(t('System disk'), '⛁', false); ui.temp = card(t('Temperature'), '🌡', true); ui.cores = h('div', {class: 'cores'}); ui.net = lineChart([{key: 'rx', label: t('received'), color: '--series-1'}, {key: 'tx', label: t('sent'), color: '--series-2'}], bitRate); ui.io = lineChart([{key: 'read', label: t('read'), color: '--series-1'}, {key: 'write', label: t('written'), color: '--series-2'}], byteRate); ui.net = lineChart([{key: 'rx', label: t('received'), color: 's1'}, {key: 'tx', label: t('sent'), color: 's2'}], bitRate); ui.io = lineChart([{key: 'read', label: t('read'), color: 's1'}, {key: 'write', label: t('written'), color: 's2'}], byteRate); ui.fs = h('div', {}); ui.ifaces = h('div', {}); ui.sensors = h('div', {}); Loading Loading @@ -302,7 +302,7 @@ // cores: one bar each, height = load ui.cores.replaceChildren(...cores.map((c, i) => h('div', {class: 'core', title: t('core {0}', i) + ': ' + pct(c)}, h('div', {class: 'core-bar'}, h('span', {class: level(c), style: `height: ${Math.max(c, 1.5)}%`})), h('div', {class: 'core-bar'}, sized(h('span', {class: level(c)}), 'height', Math.max(c, 1.5))), h('div', {class: 'core-label'}, i)))); ui.net.draw(); Loading Loading @@ -344,11 +344,18 @@ }))); } // sizes go through the CSSOM: the CSP (default-src 'self') blocks style // attributes function sized(el, prop, percent) { el.style[prop] = percent + '%'; return el; } // a horizontal meter, colored by level function bar(p) { const v = Math.max(0, Math.min(100, p || 0)); return h('div', {class: 'meter', role: 'meter', 'aria-valuenow': Math.round(v), 'aria-valuemin': 0, 'aria-valuemax': 100}, h('span', {class: level(v), style: `width: ${v}%`})); sized(h('span', {class: level(v)}), 'width', v)); } webctl.register('dashboard', { Loading Loading
www/app.css +4 −0 Changes for www/app.css: 4 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -277,6 +277,10 @@ svg.spark { display: block; width: 100%; height: 28px; margin-top: 10px; } @media (max-width: 720px) { .dash-two { grid-template-columns: 1fr; } } .legend { display: flex; flex-wrap: wrap; gap: 4px 16px; font-size: .9em; color: var(--muted); margin-bottom: 6px; } .legend b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; } .swatch.s1, .chart-area.s1, .chart-dot.s1 { background: var(--series-1); fill: var(--series-1); } .swatch.s2, .chart-area.s2, .chart-dot.s2 { background: var(--series-2); fill: var(--series-2); } .chart-line.s1 { stroke: var(--series-1); } .chart-line.s2 { stroke: var(--series-2); } .swatch { display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin-right: .4em; vertical-align: -1px; } .chart-plot { position: relative; touch-action: pan-y; } .chart-svg { display: block; } Loading
www/modules/dashboard.js +16 −9 Changes for www/modules/dashboard.js: 16 added lines, 9 removed lines. Original line number Diff line number Diff line Loading @@ -118,7 +118,7 @@ const svg = s('svg', {class: 'chart-svg', height: H, role: 'img'}); const tip = h('div', {class: 'chart-tip', hidden: true}); const legend = h('div', {class: 'legend'}, series.map(sr => h('span', {}, h('i', {class: 'swatch', style: `background: var(${sr.color})`}), sr.label, ' ', h('b', {class: 'legend-value'})))); h('span', {}, h('i', {class: 'swatch ' + sr.color}), sr.label, ' ', h('b', {class: 'legend-value'})))); const plot = h('div', {class: 'chart-plot'}, svg, tip); const el = h('div', {class: 'chart'}, legend, plot); let hover = null; // index under the pointer Loading Loading @@ -153,18 +153,18 @@ if (n >= 2) { for (const sr of series) { const d = hist[sr.key].map((v, i) => (i ? 'L' : 'M') + x(i).toFixed(1) + ' ' + y(v).toFixed(1)).join(''); kids.push(s('path', {d: d + `L${x(n - 1).toFixed(1)} ${y(0)}L${x(0).toFixed(1)} ${y(0)}Z`, class: 'chart-area', style: `fill: var(${sr.color})`})); kids.push(s('path', {d, class: 'chart-line', style: `stroke: var(${sr.color})`})); kids.push(s('path', {d: d + `L${x(n - 1).toFixed(1)} ${y(0)}L${x(0).toFixed(1)} ${y(0)}Z`, class: 'chart-area ' + sr.color})); kids.push(s('path', {d, class: 'chart-line ' + sr.color})); } } if (hover !== null && hover < n) { const xx = x(hover); kids.push(s('line', {x1: xx, x2: xx, y1: PAD.t, y2: PAD.t + ph, class: 'crosshair'})); for (const sr of series) kids.push(s('circle', {cx: xx, cy: y(hist[sr.key][hover]), r: 4, class: 'chart-dot', style: `fill: var(${sr.color})`})); kids.push(s('circle', {cx: xx, cy: y(hist[sr.key][hover]), r: 4, class: 'chart-dot ' + sr.color})); const ago = Math.round((hist.at[n - 1] - hist.at[hover]) / 1000); tip.replaceChildren(h('div', {class: 'muted'}, ago ? t('{0} ago', ago + ' s') : t('now')), series.map(sr => h('div', {}, h('i', {class: 'swatch', style: `background: var(${sr.color})`}), sr.label + ': ', ...series.map(sr => h('div', {}, h('i', {class: 'swatch ' + sr.color}), sr.label + ': ', h('b', {}, format(hist[sr.key][hover]))))); tip.hidden = false; const left = xx + 12 + tip.offsetWidth > W ? xx - 12 - tip.offsetWidth : xx + 12; Loading Loading @@ -217,8 +217,8 @@ ui.disk = card(t('System disk'), '⛁', false); ui.temp = card(t('Temperature'), '🌡', true); ui.cores = h('div', {class: 'cores'}); ui.net = lineChart([{key: 'rx', label: t('received'), color: '--series-1'}, {key: 'tx', label: t('sent'), color: '--series-2'}], bitRate); ui.io = lineChart([{key: 'read', label: t('read'), color: '--series-1'}, {key: 'write', label: t('written'), color: '--series-2'}], byteRate); ui.net = lineChart([{key: 'rx', label: t('received'), color: 's1'}, {key: 'tx', label: t('sent'), color: 's2'}], bitRate); ui.io = lineChart([{key: 'read', label: t('read'), color: 's1'}, {key: 'write', label: t('written'), color: 's2'}], byteRate); ui.fs = h('div', {}); ui.ifaces = h('div', {}); ui.sensors = h('div', {}); Loading Loading @@ -302,7 +302,7 @@ // cores: one bar each, height = load ui.cores.replaceChildren(...cores.map((c, i) => h('div', {class: 'core', title: t('core {0}', i) + ': ' + pct(c)}, h('div', {class: 'core-bar'}, h('span', {class: level(c), style: `height: ${Math.max(c, 1.5)}%`})), h('div', {class: 'core-bar'}, sized(h('span', {class: level(c)}), 'height', Math.max(c, 1.5))), h('div', {class: 'core-label'}, i)))); ui.net.draw(); Loading Loading @@ -344,11 +344,18 @@ }))); } // sizes go through the CSSOM: the CSP (default-src 'self') blocks style // attributes function sized(el, prop, percent) { el.style[prop] = percent + '%'; return el; } // a horizontal meter, colored by level function bar(p) { const v = Math.max(0, Math.min(100, p || 0)); return h('div', {class: 'meter', role: 'meter', 'aria-valuenow': Math.round(v), 'aria-valuemin': 0, 'aria-valuemax': 100}, h('span', {class: level(v), style: `width: ${v}%`})); sized(h('span', {class: level(v)}), 'width', v)); } webctl.register('dashboard', { Loading