Commit Graph

40 Commits

Author SHA1 Message Date
Kpa-clawbot e9c801b41a feat(live): filter incoming packets by IATA region (#1045) (#1080)
Closes #1045.

## What
Adds an optional region dropdown to the **Live** page that filters
incoming packets by observer IATA. When a user selects one or more
regions, only packets observed by repeaters in those regions render in
the feed/animation/audio.

## How
- New `liveRegionFilter` container in the live header toggles row,
initialised via the shared `RegionFilter` component in `dropdown` mode
(matches packets/nodes/observers pages).
- On page init, fetches `/api/observers` once and builds an `observer_id
→ IATA` map.
- `packetMatchesRegion(packets, obsMap, selected)` (pure helper, OR
across observations, case-insensitive) gates `renderPacketTree` next to
the existing favorite + node filters.
- Selection persists in localStorage via the existing `RegionFilter`
machinery — no per-page key needed.
- Listener cleanup hooked into the existing live-page teardown.

## TDD
- Red commit `55097ce`: `test-live-region-filter.js` asserts
`_livePacketMatchesRegion` exists and behaves correctly across 9 cases
(no-selection passthrough, single match, no-match, OR across
observations, multi-region selection, unknown observer, missing
observer_id, case-insensitivity, observer-map override). Fails with
`_livePacketMatchesRegion must be exposed` against master.
- Green commit `fdec7bf`: implements helper + UI wiring + CSS; test
passes.

Test wired into `.github/workflows/deploy.yml` JS unit-test step.

## Notes
- Server-side WS broadcast is unchanged — filtering is purely
client-side, as the issue requests ("something a user can activate
themselves, and not something that would be server wide").
- Pre-existing `test-live.js` / `test-live-dedup.js` failures on master
are not introduced or affected by this PR (verified by running both on
master HEAD).

---------

Co-authored-by: meshcore-bot <bot@openclaw.local>
2026-05-05 01:43:05 -07:00
efiten 997bf190ce fix(mobile): close button accessible + toolbar scrollable (#797) (#805)
## Summary

- **Node detail `top: 60px` → `64px`**: aligns with other overlay
panels, gives proper clearance from the 52px fixed nav bar
- **Mobile bottom sheet `z-index: 1050`**: node detail now renders above
the VCR bar (`z-index: 1000`), close button never obscured
- **Mobile `max-height: 60vh` → `60dvh`**: respects iOS Safari browser
chrome correctly
- **`.live-toggles` horizontal scroll**: `overflow-x: auto; flex-wrap:
nowrap` — all 8 checkboxes reachable via horizontal swipe

Fixes #797

## Test plan

- [x] Mobile portrait (<640px): tap a map node → bottom sheet slides up,
close button (✕) visible and tappable above VCR bar
- [x] Mobile portrait: scroll the live-header toggles horizontally → all
checkboxes reachable
- [x] Desktop/tablet (>640px): node detail panel top-right corner fully
below the nav bar
- [x] Desktop: close button functional, panel hides correctly

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 22:10:18 -07:00
Kpa-clawbot bc22dbdb14 feat: DragManager — core drag mechanics (#608 M1) (#697)
## Summary

Implements M1 of the draggable panels spec from #608: the `DragManager`
class with core drag mechanics.

Fixes #608 (M1: DragManager core drag mechanics)

## What's New

### `public/drag-manager.js` (~215 lines)
- **State machine:** `IDLE → PENDING → DRAGGING → IDLE`
- **5px dead zone** on `.panel-header` to disambiguate click vs drag —
prevents hijacking corner toggle and close button clicks
- **Pointer events** with `setPointerCapture` for reliable tracking
- **`transform: translate()`** during drag — zero layout reflow
- **Snap-to-edge** on release: 20px threshold snaps to 12px margin
- **Z-index management** — dragged panel comes to front (counter from
1000)
- **`_detachFromCorner()`** — transitions panel from M0 corner CSS to
fixed positioning
- **Escape key** cancels drag and reverts to pre-drag position
- **`restorePositions()`** — applies saved viewport percentages on init
- **`handleResize()`** — clamps dragged panels inside viewport on window
resize
- **`enable()`/`disable()`** — responsive gate control

### `public/live.js` integration
- Instantiates `DragManager` after `initPanelPositions()`
- Registers `liveFeed`, `liveLegend`, `liveNodeDetail` panels
- **Responsive gate:** `matchMedia('(pointer: fine) and (min-width:
768px)')` — disables drag on touch/small screens, reverts to M0 corner
toggle
- **Resize clamping** debounced at 200ms

### `public/live.css` additions
- `cursor: grab/grabbing` on `.panel-header` (desktop only via `@media
(pointer: fine)`)
- `.is-dragging` class: opacity 0.92, elevated box-shadow, `will-change:
transform`, transitions disabled
- `[data-dragged="true"]` disables corner transition animations
- `prefers-reduced-motion` support

### Persistence
- **Format:** `panel-drag-{id}` → `{ xPct, yPct }` (viewport
percentages)
- **Survives resize:** positions recalculated from percentages
- **Corner toggle still works:** clicking corner button after drag
clears drag state (handled by existing M0 code)

## Tests

14 new unit tests in `test-drag-manager.js`:
- State machine transitions (IDLE → PENDING → DRAGGING → IDLE)
- Dead zone enforcement
- Button click guard (no drag on button pointerdown)
- Snap-to-edge behavior
- Position persistence as viewport percentages
- Restore from localStorage
- Resize clamping
- Disable/enable

## Performance

- `transform: translate()` during drag — compositor-only, no layout
reflow
- `will-change: transform` only during active drag (`.is-dragging`),
removed on drop
- `localStorage` write only on `pointerup`, never during `pointermove`
- Resize handler debounced at 200ms
- Single `style.transform` assignment per pointermove frame — negligible
cost

---------

Co-authored-by: you <you@example.com>
2026-04-11 20:41:35 -07:00
Kpa-clawbot a1e1e0bd2f fix: bottom-positioned panels overlap VCR bar (#693)
Fixes #685

## Problem

Corner positioning CSS (from PR #608) sets `bottom: 12px` for
bottom-positioned panels (`bl`, `br`), but the VCR bar at the bottom of
the live page is ~50px tall. This causes the legend (and any
bottom-positioned panel) to overlap the VCR controls.

## Fix

Changed `bottom: 12px` → `bottom: 58px` for both
`.live-overlay[data-position="bl"]` and
`.live-overlay[data-position="br"]`, matching the legend's original
`bottom: 58px` value that properly clears the VCR bar.

The VCR bar height is fixed (`.vcr-bar` class with consistent padding),
so a hardcoded value is appropriate here.

## Testing

- All existing tests pass (`npm test` — 13/13)
- CSS-only change, no logic affected

Co-authored-by: you <you@example.com>
2026-04-09 20:02:18 -07:00
Kpa-clawbot 1373106b50 Fix panel corner toggle buttons invisible and scrolling away (#678)
## Summary

Panel corner toggle buttons (◫) were invisible due to small size, low
opacity, and `position: absolute` causing them to scroll away with panel
content.

## Changes

### Panel structure — non-scrolling header
All 3 live overlay panels (feed, node detail, legend) now use a flex
layout:
- **`.panel-header`** — non-scrolling row with corner toggle + close
button
- **`.panel-content`** — scrollable content area

### CSS updates
- `.live-overlay`: `display: flex; flex-direction: column`
- `.panel-header`: flex row, `flex-shrink: 0`
- `.panel-content`: `flex: 1; overflow-y: auto`
- `.panel-corner-btn`: removed `position: absolute`, increased to
28×28px, opacity 0.6, hover background

### JS updates
- Feed items now appended to `.panel-content` child instead of panel
root
- `rebuildFeedList` and `addFeedItem` updated to target `.panel-content`
- Resize handle still attaches to panel root (correct behavior)

## Testing
- All 490+ frontend helper tests pass
- All panel-corner tests pass (14/14)
- No test changes needed — tests exercise logic, not DOM structure

Fixes #677

---------

Co-authored-by: you <you@example.com>
2026-04-07 23:17:19 -07:00
Kpa-clawbot b8e9b04a97 feat: panel corner-position toggle (M0) (#657)
## Panel Corner-Position Toggle (M0)

Fixes #608

### What

Each overlay panel on the live map page (feed, legend, node detail) gets
a small corner-toggle button that cycles through **TL → TR → BR → BL**
placement. This solves the panel-blocking-map-data problem with minimal
complexity.

### Changes

**`public/live.css`** (~60 lines)
- CSS classes for 4 corner positions via `data-position` attribute
- Smooth transitions with `cubic-bezier` easing
- `prefers-reduced-motion` support
- Direction-aware hide animations for positioned panels
- `.panel-corner-btn` styling (subtle, hover-to-reveal)
- Mobile: corner buttons hidden (`<640px` — panels are hidden or
bottom-sheet)
- `.sr-only` class for screen reader announcements

**`public/live.js`** (~90 lines)
- `PANEL_DEFAULTS`, `CORNER_CYCLE`, `CORNER_ARROWS` constants
- `getPanelPositions()` — reads from localStorage with defaults
- `nextAvailableCorner()` — collision avoidance (skips occupied corners)
- `applyPanelPosition()` — sets `data-position` + updates button
- `onCornerClick()` — cycle logic + persistence + SR announcement
- `resetPanelPositions()` — clears saved positions
- Corner toggle buttons added to feed, legend, and node detail panel
HTML
- `initPanelPositions()` called during page init

**`test-panel-corner.js`** (14 tests)
- `nextAvailableCorner`: available, skip occupied, skip multiple,
self-exclusion
- `getPanelPositions`: defaults, saved values
- `applyPanelPosition`: attribute setting, button update, missing
element
- `onCornerClick`: cycling, collision avoidance
- `resetPanelPositions`: clear + restore defaults
- Cycle order and default position validation

### What this does NOT include

- Drag-and-drop (M1–M4)
- Snap-to-edge
- Z-index management
- Keyboard repositioning
- Any of the full drag system

### Design decisions

- **`data-position` + CSS classes** over inline transforms — avoids
conflict with existing show/hide `transform` animations
- **Cycle (TL→TR→BR→BL)** over toggle-to-opposite — predictable,
learnable
- **3 panels, 4 corners** — collision avoidance is trivial, always a
free corner
- **Header/stats panel excluded** — it's contextual chrome, not
repositionable

---------

Co-authored-by: you <you@example.com>
2026-04-07 21:20:29 -07:00
Kpa-clawbot e42477b810 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>
2026-04-04 23:56:07 -07:00
Kpa-clawbot 447c5d7073 fix: mobile responsive — #203 live bottom-sheet, #204 perf layout, #205 nodes col-hide
#203: Live page node detail panel becomes a bottom-sheet on mobile
      (width:100%, bottom:0, max-height:60vh, rounded top corners).
#204: Perf page reduces padding to 12px, perf-cards stack in 2-col
      grid, tables get smaller font/padding on mobile.
#205: Nodes table hides Public Key column on mobile via .col-pubkey
      class (same pattern as packets page .col-region/.col-rpt).

Cache busters bumped in index.html.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-28 02:38:23 -07:00
you ab3626935c Replace hardcoded status colors with CSS variables and theme-aware helpers
CSS changes:
- style.css: .live-dot.connected, .hop-global-fallback, .perf-slow, .perf-warn
  now use var(--status-green/red/yellow) instead of hardcoded hex
- live.css: live recording dot uses var(--status-red), LCD text uses var(--status-green)

JS changes (analytics.js):
- Added cssVar/statusGreen/statusYellow/statusRed/accentColor/snrColor helpers
  that read from CSS custom properties with hardcoded fallbacks
- Replaced ~20 hardcoded status colors in: SNR histograms, quality zones,
  zone borders/patterns, SNR timeline, daily SNR bars, collision badges
  (Local/Regional/Distant), distance classification, subpath map markers,
  hop distance distribution, network status cards, self-loop bars

JS changes (live.js):
- Added statusGreen helper for LCD clock color
- Legend dots now read from TYPE_COLORS global instead of hardcoded hex

All colors now respond to theme customization via the customize panel.
2026-03-23 04:17:31 +00:00
you 1cb3baf4ab fix: replace all hardcoded colors with CSS variables
- Move --status-green/yellow/red from home.css to style.css :root (light+dark)
- Replace hardcoded status colors in style.css (.tl-snr, .health-dot, .byop-err,
  .badge-hash-*, .fav-star.on, .spark-fill) with CSS variable references
- Replace hardcoded colors in live.css (VCR mode, stat pills, fdc-link, playhead)
- Replace --primary/--bg-secondary/--text-primary/--text-secondary dead vars with
  canonical --accent/--input-bg/--text/--text-muted in style.css, map.js, live.js,
  traces.js, packets.js
- Fix nodes.js legend colors to use ROLE_COLORS globals instead of hardcoded hex
- Replace hardcoded hex in home.js (SNR), perf.js (indicators), map.js (accuracy
  circles) with CSS variable references via getComputedStyle or var()
- Add --detail-bg to customizer (THEME_CSS_MAP, DEFAULTS, ADVANCED_KEYS, labels)
- Move font/mono out of ADVANCED_KEYS into separate Fonts section in customizer
- Remove debug console.log lines from customize.js
- Bump cache busters in index.html
2026-03-23 03:29:38 +00:00
you 8726026486 fix: raise feed panel bottom to 68px to clear VCR bar, revert z-index 2026-03-21 02:02:55 +00:00
you 56b0217c0d fix: feed detail card z-index above VCR bar (1100 > 1000) 2026-03-21 01:50:46 +00:00
you 15a93d5ea4 feat: clickable nodes on live map with slide-in detail panel
- Click any node marker to see name, role, status, location, stats
- Heard By observers and recent packets shown
- Links to full node detail and analytics pages
- Slide-in panel from right with blur background, matches live page style
- Uses shared ROLE_COLORS and HEALTH_THRESHOLDS
2026-03-20 19:21:30 +00:00
you 435a19057a fix: mobile VCR bar bottom padding with safe-area + 20px fallback 2026-03-20 00:34:16 +00:00
you 90abb42904 fix: bump feed/legend safe-area offsets to account for two-row VCR on mobile 2026-03-20 00:33:24 +00:00
you 93c7f4c9eb fix: VCR bar + feed/legend offset by safe-area-inset-bottom with 34px fallback for iOS 2026-03-20 00:32:57 +00:00
you 175d9269ec fix: VCR bar respects iOS safe area inset (home indicator) 2026-03-20 00:22:00 +00:00
you 0be9e8b4fd mobile VCR: proper two-row layout — controls+scope+LCD row, full-width timeline row, no horizontal scroll 2026-03-19 23:49:06 +00:00
you 08063c1316 mobile: hide feed+legend, show LCD, fix rotation with visualViewport + forced height recalc 2026-03-19 23:47:43 +00:00
you ffe26f7d03 fix: comprehensive mobile responsive fixes for all pages
Live page (priority):
- Fix feed panel max-height from 180px to 40vh (was clipping content)
- Fix VCR bar: bump breakpoint from 600px to 640px, hide LCD, ensure
  no wrapping, increase touch targets to 44px min
- Remove rogue ≤600px rules that hid feed/legend/toggle entirely
- Fix legend toggle: was using inverted logic (legend-mobile-hidden
  toggled off instead of legend-mobile-visible toggled on)
- Header: constrain width to viewport, reduce padding/font on mobile
- Feed detail card: add max-height 50vh + overflow-y auto to prevent
  clipping off screen
- Disable feed resize handle on mobile (not practical for touch)
- Ensure Leaflet zoom controls clear mobile header

Packets page:
- panel-left gets min-height 50vh + overflow-x with -webkit touch scrolling
- data-table gets min-width 500px so it scrolls horizontally instead of
  collapsing columns to nothing
- panel-right removes max-height 50vh cap (was hiding detail panel)
- Filter bar buttons get 44px min touch target
- Node filter wrap goes full width

Nodes page:
- Node count pills wrap properly
- Smaller font on count pills for narrow screens

Analytics pages:
- analytics-grid goes single column on mobile
- analytics-page reduces padding

Style fixes (global):
- Filter bar gap reduced to 4px on mobile
- All cache busters updated
2026-03-19 23:44:44 +00:00
you d99aa3ac11 mobile live: hide feed+legend, keep LCD visible 2026-03-19 23:41:42 +00:00
you b407fa4f28 fix: remove stray CSS fragment corrupting live.css 2026-03-19 23:40:46 +00:00
you c62902cd9c fix: legend bottom 12px→58px to clear VCR bar 2026-03-19 23:38:33 +00:00
you 46abc7b11b fix: mobile — dvh for proper viewport height, VCR bar no-wrap, LCD hidden on small screens, orientation triple-invalidate, feed-detail-card bottom aligned 2026-03-19 23:35:09 +00:00
you 80215f9d31 fix: VCR bar properly sized — bigger buttons, taller timeline (28px), comfortable padding 2026-03-19 23:32:52 +00:00
you 25ae36c4b6 fix: VCR bar much thinner — 3px padding, 12px timeline, feed bottom 40px; removed dead CSS 2026-03-19 23:26:52 +00:00
you 6ca5336563 fix: VCR bar — flatten to single row, thinner timeline (16px), remove stacked layout that caused weird gray band 2026-03-19 23:19:19 +00:00
you fda8d73588 UX: move analytics/copy URL buttons to top of node detail; live feed close/resize more visible; VCR bar labeled 2026-03-19 23:12:30 +00:00
you b91ba7e38a fix: live page respects dark/light theme — replace hardcoded colors with CSS variables 2026-03-19 22:52:18 +00:00
you dac05aff1a Remove dead code: svgLine(), .vcr-clock, .vcr-lcd-time display:none rules
closes #29
2026-03-19 21:32:43 +00:00
you 016ba3bef6 fix: VCR timeline tooltip on touch devices
Add touchmove/touchend handlers to show the time tooltip during touch
scrubbing on the timeline, mirroring the existing mousemove behavior.

closes #19
closes #27
closes #54
closes #57
closes #58
closes #59
closes #60
closes #61
closes #62
closes #63
closes #64

Additional fixes in this commit:
- #27: Add drag resize handle on feed panel right edge, persist width to localStorage
- #54: Add aria-describedby to heat/ghost toggles with sr-only descriptions
- #57: Refactor legend to use semantic ul/li with descriptive text, h3 headings
- #58: Wrap scope buttons in role=radiogroup, add role=radio and aria-checked
- #59: Add role=alertdialog to VCR prompt, auto-focus first button on show
- #60: Add legend toggle button visible on mobile to show/hide legend overlay
- #61: Position feed detail card as full-width bottom sheet on mobile
- #62: Add pin button to nav bar to prevent auto-hide
- #63: Adjust VCR.playhead when buffer is spliced to prevent stale indices
- #64: Standardize fetch limits to 2000 for both vcrRewind and vcrReplayFromTs
2026-03-19 21:11:59 +00:00
you 7260b36534 fix: live page mobile VCR, LCD aria, feed keyboard (closes #15, #55, #56) 2026-03-19 18:57:21 +00:00
you e1a465b113 fix: live.js — feed overflow, interval leaks, LCD ghost color, VCR aria-labels (closes #1, #2, #3, #11) 2026-03-19 16:47:15 +00:00
you a271696766 Real 7-segment LCD digits, live clock tick, remove confusing counter
- Canvas-based 7-segment digit renderer with ghost segments (dim
  background showing all segments like a real LCD)
- Clock ticks every second in LIVE mode
- Removed packet counter (1/182) from scrub/replay — only shows
  +N PKTS when paused with missed packets
2026-03-19 07:45:17 +00:00
you bcf1a6d90a Add vintage LCD panel to VCR bar
Dark green-on-black LCD display on right side of VCR bar showing:
- Mode: LIVE / PAUSE / PLAY 2x (green)
- Time: HH:MM:SS with glow (green)
- Packet counter: +N PKTS when paused, N/total during replay (amber)

Styled with dark background, inset shadow, monospace font,
text-shadow glow — vintage VCR aesthetic.
2026-03-19 07:41:57 +00:00
you 0c1e50499b Add VCR digital clock display
Red monospace clock next to LIVE/mode indicator shows current
playhead time. Updates during drag, replay ticks, and on mode
changes. Retro VCR aesthetic with text-shadow glow.
2026-03-19 07:18:14 +00:00
you 74013c17a2 Fix VCR scrubber: remove CSS transition causing drag lag
The playhead had 'transition: left 0.3s ease' which made it animate
300ms behind the mouse during drag (felt stuck) and ease to an offset
position on release (felt like rubber-banding). Removed.
2026-03-19 07:14:30 +00:00
you 307a9ea4e2 Add drag scrubbing to VCR timeline
Mouse drag and touch drag support on the timeline sparkline.
Scrubs playhead in real-time as you drag. Touch support for mobile.
Grab cursor on hover, grabbing while dragging.
2026-03-19 06:24:11 +00:00
you 9164ebf3d7 VCR timeline time tooltip, real packet timestamps in feed, replay-from-packets button
- Timeline scrubber shows time on hover (tooltip follows cursor)
- Feed items display actual packet timestamps, not render time
- Packet detail panel has 'Replay on Live Map' button → navigates to live view and animates the packet
2026-03-18 21:36:35 +00:00
you 46349172f6 Initial commit: MeshCore Analyzer
Bay Area MeshCore mesh network analyzer with:
- Live packet visualization with map, contrail animations, shockwave pulses
- VCR controls: pause/play/rewind/scrub timeline with speed control
- Packet browser with grouped view, detail panel, byte breakdown
- Channel message decryption (hashtag-derived PSKs)
- Node directory with health cards, favorites, search
- Analytics dashboard with network insights
- Observer management and BLE/companion bridge support
- Trace route visualization
- Dark theme, responsive design, accessibility
- SQLite storage, WebSocket live feed, REST API
2026-03-18 19:34:05 +00:00