mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-07-12 03:38:52 +00:00
feat: collapsible panels + medium breakpoint on live map (#606)
## Summary Adds collapsible/minimizable UI panels on the live map page so overlay panels don't block map content on medium-sized screens. Fixes #279 ## Changes ### Collapsible Legend Panel (all screen sizes) - The legend toggle button (🎨/✕) is now visible at **all** screen sizes, not just mobile - Clicking it smoothly collapses/expands the legend with a CSS transition - Collapsed state persists in `localStorage` (`live-legend-hidden`) - Feed panel already had hide/show with localStorage — no changes needed there ### Medium Breakpoint (768px) New `@media (max-width: 768px)` rules for tablet/small laptop screens: - Feed panel: 360px → 280px wide, max-height 340px → 200px - Node detail panel: 320px → 260px wide - Legend: smaller font (10px) and tighter padding - Header: reduced gap and padding - Stats/toggles: smaller font sizes ### What's NOT changed - Mobile (≤640px): existing behavior preserved (feed/legend hidden entirely) - Desktop (>768px): no changes — panels render at full size as before ## Testing - `test-packet-filter.js`: 62 passed - `test-aging.js`: 29 passed - `test-frontend-helpers.js`: 445 passed --------- Co-authored-by: you <you@example.com>
This commit is contained in:
+20
-2
@@ -201,6 +201,15 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
transition: opacity 0.3s, transform 0.3s;
|
||||
}
|
||||
|
||||
/* Collapsible legend (#279) */
|
||||
.live-legend.hidden {
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
pointer-events: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.legend-title {
|
||||
@@ -272,6 +281,16 @@
|
||||
background: rgba(59, 130, 246, 0.2) !important;
|
||||
}
|
||||
|
||||
/* ---- Medium breakpoint (#279) ---- */
|
||||
@media (max-width: 768px) {
|
||||
.live-feed { width: 280px; max-height: 200px; }
|
||||
.live-node-detail { width: 260px; }
|
||||
.live-legend { font-size: 10px; padding: 8px 10px; }
|
||||
.live-header { gap: 8px; padding: 6px 12px; }
|
||||
.live-stat-pill { font-size: 11px; padding: 2px 8px; }
|
||||
.live-toggles { font-size: 10px; gap: 6px; }
|
||||
}
|
||||
|
||||
/* ---- Responsive ---- */
|
||||
@media (max-width: 640px) {
|
||||
.live-feed { display: none !important; }
|
||||
@@ -702,9 +721,8 @@
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* Legend toggle button for mobile (#60) */
|
||||
/* Legend toggle button — visible at all sizes (#60, #279) */
|
||||
.legend-toggle-btn {
|
||||
display: none;
|
||||
position: absolute;
|
||||
bottom: 82px;
|
||||
right: 12px;
|
||||
|
||||
+13
-4
@@ -762,7 +762,7 @@
|
||||
<button class="feed-hide-btn" id="nodeDetailClose" title="Close">✕</button>
|
||||
<div id="nodeDetailContent"></div>
|
||||
</div>
|
||||
<button class="legend-toggle-btn hidden" id="legendToggleBtn" aria-label="Show legend" title="Show legend">🎨</button>
|
||||
<button class="legend-toggle-btn" id="legendToggleBtn" aria-label="Show legend" title="Show legend">🎨</button>
|
||||
<div class="live-overlay live-legend" id="liveLegend" role="region" aria-label="Map legend">
|
||||
<h3 class="legend-title">PACKET TYPES</h3>
|
||||
<ul class="legend-list">
|
||||
@@ -1043,10 +1043,19 @@
|
||||
const legendEl = document.getElementById('liveLegend');
|
||||
const legendToggleBtn = document.getElementById('legendToggleBtn');
|
||||
if (legendToggleBtn && legendEl) {
|
||||
// Restore legend collapsed state from localStorage (#279)
|
||||
try {
|
||||
if (localStorage.getItem('live-legend-hidden') === 'true') {
|
||||
legendEl.classList.add('hidden');
|
||||
legendToggleBtn.setAttribute('aria-label', 'Show legend');
|
||||
legendToggleBtn.textContent = '🎨';
|
||||
}
|
||||
} catch (_) { /* private browsing / storage disabled */ }
|
||||
legendToggleBtn.addEventListener('click', () => {
|
||||
const isVisible = legendEl.classList.toggle('legend-mobile-visible');
|
||||
legendToggleBtn.setAttribute('aria-label', isVisible ? 'Hide legend' : 'Show legend');
|
||||
legendToggleBtn.textContent = isVisible ? '✕' : '🎨';
|
||||
const nowHidden = legendEl.classList.toggle('hidden');
|
||||
legendToggleBtn.setAttribute('aria-label', nowHidden ? 'Show legend' : 'Hide legend');
|
||||
legendToggleBtn.textContent = nowHidden ? '🎨' : '✕';
|
||||
try { localStorage.setItem('live-legend-hidden', String(nowHidden)); } catch (_) { /* ignore */ }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user