feat: optimize topology member overlay

This commit is contained in:
2025-08-30 21:28:36 +02:00
parent bebf979860
commit 91ff24c162
2 changed files with 101 additions and 61 deletions

View File

@@ -3061,8 +3061,23 @@ class MemberCardOverlayComponent extends Component {
return ` return `
<div class="member-overlay-content"> <div class="member-overlay-content">
<div class="member-overlay-header"> <div class="member-overlay-header">
<div class="member-overlay-title"> <div class="member-info">
<h3>Member Details</h3> <div class="member-row-1">
<div class="status-hostname-group">
<div class="member-status ${statusClass}">
${statusIcon}
</div>
<div class="member-hostname">${member.hostname || 'Unknown Device'}</div>
</div>
<div class="member-ip">${member.ip || 'No IP'}</div>
<div class="member-latency">
<span class="latency-label">Latency:</span>
<span class="latency-value">${member.latency ? member.latency + 'ms' : 'N/A'}</span>
</div>
</div>
<div class="member-labels" style="display: none;">
<!-- Labels will be populated dynamically from node status API -->
</div>
</div> </div>
<button class="member-overlay-close" aria-label="Close"> <button class="member-overlay-close" aria-label="Close">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@@ -3073,26 +3088,6 @@ class MemberCardOverlayComponent extends Component {
<div class="member-overlay-body"> <div class="member-overlay-body">
<div class="member-card expanded" data-member-ip="${member.ip}"> <div class="member-card expanded" data-member-ip="${member.ip}">
<div class="member-header">
<div class="member-info">
<div class="member-row-1">
<div class="status-hostname-group">
<div class="member-status ${statusClass}">
${statusIcon}
</div>
<div class="member-hostname">${member.hostname || 'Unknown Device'}</div>
</div>
<div class="member-ip">${member.ip || 'No IP'}</div>
<div class="member-latency">
<span class="latency-label">Latency:</span>
<span class="latency-value">${member.latency ? member.latency + 'ms' : 'N/A'}</span>
</div>
</div>
<div class="member-labels" style="display: none;">
<!-- Labels will be populated dynamically from node status API -->
</div>
</div>
</div>
<div class="member-details"> <div class="member-details">
<div class="loading-details">Loading detailed information...</div> <div class="loading-details">Loading detailed information...</div>
</div> </div>
@@ -3136,29 +3131,14 @@ class MemberCardOverlayComponent extends Component {
// Update the labels in the member header with the actual node status data // Update the labels in the member header with the actual node status data
const nodeStatus = nodeDetailsVM.get('nodeStatus'); const nodeStatus = nodeDetailsVM.get('nodeStatus');
if (nodeStatus && nodeStatus.labels) { if (nodeStatus && nodeStatus.labels) {
const labelsContainer = card.querySelector('.member-labels'); // Find the labels container in the header
const labelsContainer = document.querySelector('.member-overlay-header .member-labels');
if (labelsContainer) { if (labelsContainer) {
// Update existing labels container and show it // Update existing labels container and show it
labelsContainer.innerHTML = Object.entries(nodeStatus.labels) labelsContainer.innerHTML = Object.entries(nodeStatus.labels)
.map(([key, value]) => `<span class="label-chip">${key}: ${value}</span>`) .map(([key, value]) => `<span class="label-chip">${key}: ${value}</span>`)
.join(''); .join('');
labelsContainer.style.display = 'block'; labelsContainer.style.display = 'block';
} else {
// Create new labels container if it doesn't exist
const memberInfo = card.querySelector('.member-info');
if (memberInfo) {
const labelsDiv = document.createElement('div');
labelsDiv.className = 'member-labels';
labelsDiv.innerHTML = Object.entries(nodeStatus.labels)
.map(([key, value]) => `<span class="label-chip">${key}: ${value}</span>`)
.join('');
// Insert after latency
const latencyDiv = memberInfo.querySelector('.member-latency');
if (latencyDiv) {
latencyDiv.parentNode.insertBefore(labelsDiv, latencyDiv.nextSibling);
}
}
} }
} }

View File

@@ -443,7 +443,6 @@ p {
.member-ip { .member-ip {
font-size: 0.85rem; font-size: 0.85rem;
opacity: 0.8; opacity: 0.8;
font-family: 'Courier New', monospace;
flex-shrink: 0; flex-shrink: 0;
} }
@@ -2702,11 +2701,54 @@ p {
border-bottom: 1px solid rgba(255, 255, 255, 0.1); border-bottom: 1px solid rgba(255, 255, 255, 0.1);
} }
.member-overlay-title h3 { .member-overlay-header .member-info {
margin: 0 0 8px 0; flex: 1;
margin-right: 16px;
}
.member-overlay-header .member-info .member-row-1 {
margin-bottom: 8px;
}
.member-overlay-header .member-info .member-hostname {
font-size: 1.5rem; font-size: 1.5rem;
font-weight: 600; font-weight: 600;
color: #ecf0f1; color: #ecf0f1;
margin-bottom: 4px;
}
.member-overlay-header .member-info .member-ip {
font-size: 1rem;
color: rgba(255, 255, 255, 0.8);
margin-bottom: 4px;
}
.member-overlay-header .member-info .member-latency {
font-size: 0.9rem;
color: rgba(255, 255, 255, 0.7);
}
.member-overlay-header .member-info .member-status {
font-size: 1.2rem;
margin-right: 8px;
}
.member-overlay-header .member-info .member-labels {
margin-top: 12px;
}
.member-overlay-header .member-info .member-labels .label-chip {
display: inline-block;
margin-right: 8px;
margin-bottom: 4px;
background: rgba(30, 58, 138, 0.35);
color: #dbeafe;
padding: 0.25rem 0.6rem;
border-radius: 9999px;
font-size: 0.75rem;
border: 1px solid rgba(59, 130, 246, 0.4);
font-family: inherit;
white-space: nowrap;
} }
.member-overlay-subtitle { .member-overlay-subtitle {
@@ -2892,6 +2934,10 @@ p {
padding: 20px 20px 12px; padding: 20px 20px 12px;
} }
.member-overlay-header .member-info .member-hostname {
font-size: 1.3rem;
}
.member-overlay-body { .member-overlay-body {
padding: 20px; padding: 20px;
} }
@@ -2900,35 +2946,42 @@ p {
flex-direction: column; flex-direction: column;
} }
.member-overlay-title h3 {
font-size: 1.3rem;
}
/* Compact layout adjustments for mobile */ /* Compact layout adjustments for mobile */
.member-row-1 { .member-overlay-header .member-info .member-row-1 {
flex-direction: column; flex-direction: column;
align-items: flex-start; align-items: flex-start;
gap: 0.5rem; gap: 0.5rem;
} }
.status-hostname-group { .member-overlay-header .status-hostname-group {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
} }
.member-status, .member-overlay-header .member-status,
.member-hostname, .member-overlay-header .member-hostname,
.member-ip, .member-overlay-header .member-ip,
.member-latency { .member-overlay-header .member-latency {
flex-shrink: 1; flex-shrink: 1;
} }
/* Keep status and hostname together on mobile */ /* Keep status and hostname together on mobile */
.member-status { .member-overlay-header .member-status {
min-width: 1.3rem; min-width: 1.3rem;
min-height: 1.3rem; min-height: 1.3rem;
} }
.member-overlay-header .member-info .member-labels {
margin-top: 8px;
}
.member-overlay-header .member-info .member-labels .label-chip {
font-size: 0.7rem;
padding: 0.2rem 0.5rem;
margin-right: 6px;
margin-bottom: 3px;
}
} }
/* Compact mobile layout for overlay */ /* Compact mobile layout for overlay */
@@ -2948,33 +3001,40 @@ p {
max-height: calc(90vh - 80px); max-height: calc(90vh - 80px);
} }
.member-overlay-body .member-card .member-header {
padding: 12px 12px 0;
}
.member-overlay-body .member-card .member-details { .member-overlay-body .member-card .member-details {
padding: 0 12px; padding: 0 12px;
} }
/* Further compact layout for very small screens */ /* Further compact layout for very small screens */
.member-row-1 { .member-overlay-header .member-info .member-row-1 {
gap: 0.25rem; gap: 0.25rem;
} }
.member-hostname { .member-overlay-header .member-info .member-hostname {
font-size: 1rem; font-size: 1rem;
} }
.member-ip { .member-overlay-header .member-info .member-ip {
font-size: 0.8rem; font-size: 0.8rem;
} }
.member-status { .member-overlay-header .member-info .member-status {
font-size: 0.8rem; font-size: 0.8rem;
padding: 0.15rem; padding: 0.15rem;
min-width: 1.1rem; min-width: 1.1rem;
min-height: 1.1rem; min-height: 1.1rem;
} }
.member-overlay-header .member-info .member-labels {
margin-top: 6px;
}
.member-overlay-header .member-info .member-labels .label-chip {
font-size: 0.65rem;
padding: 0.15rem 0.4rem;
margin-right: 4px;
margin-bottom: 2px;
}
} }
/* Test page styles */ /* Test page styles */