style: upgrade dashboard vitals cards with clinical SVGs and patient demographics banner

This commit is contained in:
2026-07-13 15:23:10 +05:30
parent c5b792a2ef
commit 1340de4fc4
+201 -6
View File
@@ -428,6 +428,13 @@
0 0 0 1px rgba(0, 0, 0, 0.02);
}
.vital-card.hr:hover { border-color: rgba(220, 38, 38, 0.3); }
.vital-card.spo2:hover { border-color: rgba(8, 145, 178, 0.3); }
.vital-card.bp:hover { border-color: rgba(124, 58, 237, 0.3); }
.vital-card.rr:hover { border-color: rgba(22, 163, 74, 0.3); }
.vital-card.temp:hover { border-color: rgba(234, 88, 12, 0.3); }
.vital-card.map-card:hover { border-color: rgba(219, 39, 119, 0.3); }
.vital-card::before {
content: '';
position: absolute;
@@ -766,6 +773,98 @@
}
}
/* === Patient Clinical Info Banner === */
.patient-banner {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 24px;
background: var(--bg-card);
border: 1px solid var(--border-color);
border-radius: 20px;
box-shadow:
0 4px 6px -1px rgba(0, 0, 0, 0.02),
0 10px 15px -3px rgba(0, 0, 0, 0.03);
margin-bottom: 24px;
flex-wrap: wrap;
gap: 16px;
}
.patient-banner-group {
display: flex;
align-items: center;
gap: 12px;
}
.patient-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
background: rgba(8, 145, 178, 0.08);
color: var(--spo2-color);
display: flex;
align-items: center;
justify-content: center;
}
.patient-avatar svg {
width: 18px;
height: 18px;
}
.patient-label {
font-size: 11px;
color: var(--text-secondary);
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.patient-value-text {
font-size: 14px;
color: var(--text-primary);
font-weight: 700;
}
.patient-banner-divider {
height: 24px;
width: 1px;
background: var(--border-color);
}
.vital-svg {
stroke-width: 2.5;
transition: transform 0.3s ease;
}
.vital-card:hover .vital-svg {
transform: scale(1.1);
}
.vital-card.hr .card-icon { color: var(--hr-color); }
.vital-card.spo2 .card-icon { color: var(--spo2-color); }
.vital-card.bp .card-icon { color: var(--bp-color); }
.vital-card.rr .card-icon { color: var(--rr-color); }
.vital-card.temp .card-icon { color: var(--temp-color); }
.vital-card.map-card .card-icon { color: var(--map-color); }
@media (max-width: 768px) {
.patient-banner-divider {
display: none;
}
.patient-banner {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
}
}
@media (max-width: 480px) {
.patient-banner {
grid-template-columns: 1fr;
}
}
/* === Scrollbar === */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: transparent; }
@@ -805,6 +904,50 @@
</div>
</header>
<!-- Patient Clinical Info Banner -->
<div class="patient-banner">
<div class="patient-banner-group">
<div class="patient-avatar">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
<circle cx="12" cy="7" r="4"/>
</svg>
</div>
<div>
<div class="patient-label">Active Patient</div>
<div class="patient-value-text" id="bannerPatientName">John Doe</div>
</div>
</div>
<div class="patient-banner-divider"></div>
<div class="patient-banner-group">
<div>
<div class="patient-label">Patient ID</div>
<div class="patient-value-text" id="bannerPatientId">N/A</div>
</div>
</div>
<div class="patient-banner-divider"></div>
<div class="patient-banner-group">
<div>
<div class="patient-label">Location / Bed</div>
<div class="patient-value-text">ICU - Bed 12</div>
</div>
</div>
<div class="patient-banner-divider"></div>
<div class="patient-banner-group">
<div>
<div class="patient-label">Monitor Status</div>
<div class="patient-value-text" id="bannerMonitorModel">CMS8500</div>
</div>
</div>
<div class="patient-banner-divider"></div>
<div class="patient-banner-group">
<div>
<div class="patient-label">Last Transmission</div>
<div class="patient-value-text" id="bannerLastSeen">Never</div>
</div>
</div>
</div>
<!-- Setup Guide -->
<div class="setup-guide" id="setupGuide">
<div class="setup-guide-header" onclick="toggleSetupGuide()">
@@ -872,7 +1015,11 @@
<div class="vital-card hr" id="card-hr">
<div class="card-header">
<div class="card-label">
<div class="card-icon">❤️</div>
<div class="card-icon">
<svg class="vital-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round">
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/>
</svg>
</div>
<span class="card-name">Heart Rate</span>
</div>
<span class="status-badge offline" id="status-hr">No Data</span>
@@ -893,7 +1040,14 @@
<div class="vital-card spo2" id="card-spo2">
<div class="card-header">
<div class="card-label">
<div class="card-icon">🫁</div>
<div class="card-icon">
<svg class="vital-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round">
<path d="M7 3a3 3 0 0 0-3 3v6a3 3 0 0 0 3 3h1a2 2 0 0 0 2-2V6a3 3 0 0 0-3-3z"/>
<path d="M17 3a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3h-1a2 2 0 0 1-2-2V6a3 3 0 0 1 3-3z"/>
<path d="M9 20h6"/>
<path d="M12 16v4"/>
</svg>
</div>
<span class="card-name">SpO₂</span>
</div>
<span class="status-badge offline" id="status-spo2">No Data</span>
@@ -914,7 +1068,11 @@
<div class="vital-card bp" id="card-bp">
<div class="card-header">
<div class="card-label">
<div class="card-icon">🩸</div>
<div class="card-icon">
<svg class="vital-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 22a7 7 0 0 0 7-7c0-4.3-7-13-7-13S5 10.7 5 15a7 7 0 0 0 7 7z"/>
</svg>
</div>
<span class="card-name">Blood Pressure</span>
</div>
<span class="status-badge offline" id="status-bp">No Data</span>
@@ -935,7 +1093,13 @@
<div class="vital-card rr" id="card-rr">
<div class="card-header">
<div class="card-label">
<div class="card-icon">🌬️</div>
<div class="card-icon">
<svg class="vital-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round">
<path d="M2 8h16a4 4 0 0 1 4 4v0a4 4 0 0 1-4 4H2"/>
<path d="M6 12h12a2 2 0 0 0 2-2v0a2 2 0 0 0-2-2H6"/>
<path d="M2 16h8"/>
</svg>
</div>
<span class="card-name">Respiratory Rate</span>
</div>
<span class="status-badge offline" id="status-rr">No Data</span>
@@ -956,7 +1120,12 @@
<div class="vital-card temp" id="card-temp">
<div class="card-header">
<div class="card-label">
<div class="card-icon">🌡️</div>
<div class="card-icon">
<svg class="vital-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 14.76V3.5a2.5 2.5 0 0 0-5 0v11.26a4.5 4.5 0 1 0 5 0z"/>
<line x1="11.5" y1="5" x2="11.5" y2="13"/>
</svg>
</div>
<span class="card-name">Temperature</span>
</div>
<span class="status-badge offline" id="status-temp">No Data</span>
@@ -977,7 +1146,11 @@
<div class="vital-card map-card" id="card-map">
<div class="card-header">
<div class="card-label">
<div class="card-icon">💓</div>
<div class="card-icon">
<svg class="vital-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round">
<polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
</svg>
</div>
<span class="card-name">Mean Arterial Pressure</span>
</div>
<span class="status-badge offline" id="status-map">No Data</span>
@@ -1191,6 +1364,12 @@
});
document.getElementById('deviceId').textContent = 'Waiting...';
document.getElementById('patientId').textContent = 'Waiting...';
document.getElementById('bannerPatientId').textContent = 'N/A';
document.getElementById('bannerPatientName').textContent = 'John Doe';
document.getElementById('bannerMonitorModel').textContent = 'CMS8500';
document.getElementById('bannerLastSeen').textContent = 'Never';
lastReadingId = null;
}
@@ -1386,6 +1565,22 @@
document.getElementById('lastUpdateTime').textContent =
now.toLocaleTimeString('en-US', { hour12: false });
// Update patient clinical banner
if (data.patient_id) {
document.getElementById('bannerPatientId').textContent = data.patient_id;
document.getElementById('bannerPatientName').textContent = data.patient_name || `Patient #${data.patient_id}`;
}
if (data.device_id) {
let deviceModel = 'CMS8500';
if (data.device_id.includes('CMS7000')) {
deviceModel = 'CMS7000PLUS';
}
const parts = data.device_id.split('_');
const suffix = parts.length > 1 ? ` (${parts.pop()})` : '';
document.getElementById('bannerMonitorModel').textContent = `${deviceModel}${suffix}`;
}
document.getElementById('bannerLastSeen').textContent = now.toLocaleTimeString('en-US', { hour12: false });
// Push waveform data
pushWaveformPoint('hr', data.heart_rate);
pushWaveformPoint('spo2', data.spo2);