잔여 시간 근거를 커스텀 팝오버로 표시
This commit is contained in:
+67
-1
@@ -32,6 +32,7 @@
|
||||
statusBatteryVoltage: $('#statusBatteryVoltage'),
|
||||
statusBatterySoc: $('#statusBatterySoc'),
|
||||
statusBatteryRemaining: $('#statusBatteryRemaining'),
|
||||
batteryRuntimeTooltip: $('#batteryRuntimeTooltip'),
|
||||
spikeLogList: $('#spikeLogList'),
|
||||
haNotifyList: $('#haNotifyList'),
|
||||
customServiceList: $('#customServiceList'),
|
||||
@@ -75,6 +76,8 @@
|
||||
rebootRequesting: false,
|
||||
lang: 'en',
|
||||
theme: 'dark',
|
||||
batteryTooltipOpen: false,
|
||||
batteryTooltipText: '',
|
||||
};
|
||||
|
||||
const storageKeys = {
|
||||
@@ -718,6 +721,62 @@
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
function positionBatteryTooltip() {
|
||||
if (!state.batteryTooltipOpen || !els.statusBatteryRemaining || !els.batteryRuntimeTooltip) {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetRect = els.statusBatteryRemaining.getBoundingClientRect();
|
||||
const tip = els.batteryRuntimeTooltip;
|
||||
const margin = 14;
|
||||
tip.style.left = '0px';
|
||||
tip.style.top = '0px';
|
||||
const tipRect = tip.getBoundingClientRect();
|
||||
let left = targetRect.left;
|
||||
let top = targetRect.bottom + 10;
|
||||
|
||||
if (left + tipRect.width > window.innerWidth - margin) {
|
||||
left = window.innerWidth - tipRect.width - margin;
|
||||
}
|
||||
if (left < margin) {
|
||||
left = margin;
|
||||
}
|
||||
if (top + tipRect.height > window.innerHeight - margin) {
|
||||
top = targetRect.top - tipRect.height - 10;
|
||||
}
|
||||
if (top < margin) {
|
||||
top = margin;
|
||||
}
|
||||
|
||||
tip.style.left = `${Math.round(left)}px`;
|
||||
tip.style.top = `${Math.round(top)}px`;
|
||||
}
|
||||
|
||||
function updateBatteryTooltip(text = state.batteryTooltipText) {
|
||||
state.batteryTooltipText = text || '';
|
||||
if (!els.batteryRuntimeTooltip) return;
|
||||
|
||||
els.batteryRuntimeTooltip.textContent = state.batteryTooltipText || '-';
|
||||
if (state.batteryTooltipOpen) {
|
||||
requestAnimationFrame(positionBatteryTooltip);
|
||||
}
|
||||
}
|
||||
|
||||
function showBatteryTooltip() {
|
||||
if (!els.batteryRuntimeTooltip) return;
|
||||
state.batteryTooltipOpen = true;
|
||||
els.batteryRuntimeTooltip.dataset.open = '1';
|
||||
els.batteryRuntimeTooltip.setAttribute('aria-hidden', 'false');
|
||||
updateBatteryTooltip();
|
||||
}
|
||||
|
||||
function hideBatteryTooltip() {
|
||||
if (!els.batteryRuntimeTooltip) return;
|
||||
state.batteryTooltipOpen = false;
|
||||
delete els.batteryRuntimeTooltip.dataset.open;
|
||||
els.batteryRuntimeTooltip.setAttribute('aria-hidden', 'true');
|
||||
}
|
||||
|
||||
function renderTop(data) {
|
||||
setText(els.updated, data.generated_at || '-');
|
||||
setText(els.temp, Number(data.system?.temp_c || 0).toFixed(1) + '°C');
|
||||
@@ -912,7 +971,8 @@
|
||||
setText(els.statusBatterySoc, battery.percent === null || battery.percent === undefined ? '-' : `${Number(battery.percent).toFixed(2)}%`);
|
||||
setText(els.statusBatteryRemaining, battery.remaining?.display || '-');
|
||||
if (els.statusBatteryRemaining) {
|
||||
els.statusBatteryRemaining.title = batteryRemainingTitle(battery.remaining);
|
||||
els.statusBatteryRemaining.removeAttribute('title');
|
||||
updateBatteryTooltip(batteryRemainingTitle(battery.remaining));
|
||||
}
|
||||
if (els.statusUsers) {
|
||||
const names = String(activeUsers.names || '').trim();
|
||||
@@ -1684,6 +1744,12 @@
|
||||
els.dmesgToggle?.addEventListener('click', () => {
|
||||
setDmesgOpen(!state.dmesgOpen);
|
||||
});
|
||||
els.statusBatteryRemaining?.addEventListener('mouseenter', showBatteryTooltip);
|
||||
els.statusBatteryRemaining?.addEventListener('mouseleave', hideBatteryTooltip);
|
||||
els.statusBatteryRemaining?.addEventListener('focus', showBatteryTooltip);
|
||||
els.statusBatteryRemaining?.addEventListener('blur', hideBatteryTooltip);
|
||||
window.addEventListener('resize', positionBatteryTooltip);
|
||||
window.addEventListener('scroll', positionBatteryTooltip, true);
|
||||
[els.secondaryChartDetails, els.processDetails, els.diagnosticDetails].forEach(node => {
|
||||
node?.addEventListener('toggle', resizeChartsSoon);
|
||||
});
|
||||
|
||||
+3
-1
@@ -110,6 +110,7 @@ html[data-theme="light"] .btn.secondary{background:#d9e2ef;color:#172033}html[da
|
||||
html[data-theme="light"] .details-panel{background:#edf3fa;border-color:#b8c7da}html[data-theme="light"] .service-item{background:#e8f0f8;border-color:#b7c8dd}html[data-theme="light"] .service-name{color:#0f1f35}html[data-theme="light"] .service-desc,html[data-theme="light"] .service-meta{color:#42526a}html[data-theme="light"] .service-state{background:#f8fbff;border-color:#aebed2;color:#304057}html[data-theme="light"] .service-state.active{background:#d8f3e3;border-color:#7fc99c;color:#146c39}html[data-theme="light"] .service-state.failed{background:#ffe2e2;border-color:#e38b8b;color:#9f1d1d}html[data-theme="light"] .service-log,html[data-theme="light"] .dmesg-log{background:#f7fafc;border-color:#b9c8da;color:#0f2742}
|
||||
.resource-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}.resource-box{min-width:0}.resource-box h3{margin:0 0 9px;color:var(--sub);font-size:14px;font-weight:500}.resource-table{width:100%;min-width:620px;table-layout:fixed;border-collapse:collapse;border:1px solid var(--line);border-radius:14px;overflow:hidden}.resource-table th,.resource-table td{padding:9px 10px;border-bottom:1px solid rgba(128,145,170,.18);background:var(--input);text-align:left;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.resource-table th{background:var(--table-head);color:var(--sub);font-weight:500}.resource-table .pid{width:72px}.resource-table .metric{width:82px}.resource-table .service{width:150px}.resource-table .cmd{width:auto}
|
||||
.notice{position:fixed;right:20px;bottom:20px;min-width:220px;max-width:420px;padding:14px 16px;border-radius:14px;font-weight:500;background:var(--table-head);color:var(--text);border:1px solid var(--line);box-shadow:var(--shadow);z-index:99}.notice:empty{display:none}.notice[data-type=success]{border-color:rgba(53,196,107,.5)}.notice[data-type=error]{border-color:rgba(255,95,87,.5)}
|
||||
.status-value.interactive{cursor:help;text-decoration:underline;text-decoration-style:dotted;text-decoration-thickness:1px;text-underline-offset:4px}.runtime-tooltip{position:fixed;left:0;top:0;z-index:110;display:none;width:min(360px,calc(100vw - 28px));padding:14px 16px;border:1px solid rgba(84,101,128,.78);border-radius:16px;background:var(--card);color:var(--text);box-shadow:0 18px 48px rgba(0,0,0,.38);font-size:13px;line-height:1.5;white-space:pre-wrap;pointer-events:none}.runtime-tooltip[data-open="1"]{display:block}.runtime-tooltip::before{content:"";position:absolute;left:18px;top:-7px;width:12px;height:12px;border-left:1px solid rgba(84,101,128,.78);border-top:1px solid rgba(84,101,128,.78);background:var(--card);transform:rotate(45deg)}html[data-theme="light"] .runtime-tooltip{background:#f8fbff;border-color:#aebed2;color:#172033;box-shadow:0 18px 44px rgba(28,43,64,.18)}html[data-theme="light"] .runtime-tooltip::before{background:#f8fbff;border-color:#aebed2}
|
||||
.dialog-layer{position:fixed;inset:0;display:none;align-items:center;justify-content:center;padding:22px;background:rgba(4,7,12,.68);backdrop-filter:blur(8px);z-index:120}.dialog-layer[data-open="1"]{display:flex}.dialog-box{width:min(430px,100%);border:1px solid rgba(84,101,128,.78);border-radius:20px;background:var(--card);box-shadow:0 24px 70px rgba(0,0,0,.42);padding:20px}.dialog-box h3{margin:0 0 8px;font-size:19px;font-weight:500}.dialog-message{margin:0 0 16px;color:var(--sub);line-height:1.5;white-space:pre-wrap}.dialog-input{width:100%;height:48px;margin-bottom:14px;border-radius:14px;border:1px solid var(--line);background:var(--input);color:var(--text);padding:0 14px;outline:none}.dialog-input:focus{outline:2px solid rgba(59,130,246,.65);outline-offset:2px}.dialog-actions{display:flex;justify-content:flex-end;gap:10px}.dialog-actions .btn{min-width:84px}.dialog-actions .btn.red{background:#c62828}
|
||||
@media(max-width:1320px){.chart-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
|
||||
@media(max-width:1100px){.layout{grid-template-columns:1fr}.chart-grid,.resource-grid{grid-template-columns:1fr}.topbar{align-items:flex-start;flex-direction:column}.topbar-right{width:100%}.topbar-right .btn{flex:1}.stat-grid{grid-template-columns:1fr}.resource-head{align-items:flex-start;flex-direction:column}.baseline-pill{text-align:left;white-space:normal}}
|
||||
@@ -194,7 +195,7 @@ html[data-theme="light"] .details-panel{background:#edf3fa;border-color:#b8c7da}
|
||||
<div class="status-row"><div class="status-key" data-i18n="throttlingRecent">Throttle 10m</div><div class="status-value" id="statusThrottlingRecent">-</div></div>
|
||||
<div class="status-row"><div class="status-key" data-i18n="batteryV">Battery V</div><div class="status-value" id="statusBatteryVoltage">-</div></div>
|
||||
<div class="status-row"><div class="status-key" data-i18n="batterySoc">Battery SOC</div><div class="status-value" id="statusBatterySoc">-</div></div>
|
||||
<div class="status-row"><div class="status-key" data-i18n="remaining">Remaining</div><div class="status-value" id="statusBatteryRemaining">-</div></div>
|
||||
<div class="status-row"><div class="status-key" data-i18n="remaining">Remaining</div><div class="status-value interactive" id="statusBatteryRemaining" tabindex="0" aria-describedby="batteryRuntimeTooltip">-</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -315,6 +316,7 @@ html[data-theme="light"] .details-panel{background:#edf3fa;border-color:#b8c7da}
|
||||
</section>
|
||||
</div>
|
||||
<div id="notice" class="notice"></div>
|
||||
<div id="batteryRuntimeTooltip" class="runtime-tooltip" role="tooltip" aria-hidden="true"></div>
|
||||
<div id="customDialog" class="dialog-layer" aria-hidden="true">
|
||||
<div class="dialog-box" role="dialog" aria-modal="true" aria-labelledby="customDialogTitle">
|
||||
<h3 id="customDialogTitle">확인</h3>
|
||||
|
||||
Reference in New Issue
Block a user