mirror of
https://github.com/zvx-echo6/meshai.git
synced 2026-05-21 23:24:44 +02:00
feat(config): add comprehensive field documentation with info buttons
- Add helper text and info (?) buttons to every field in Config.tsx - Add section descriptions at the top of each config section - Battery thresholds now show voltage equivalents (e.g., "30% ≈ 3.60V") - NWS severity dropdown shows descriptions per option - Alert rules grouped by category with full explanations - Add InfoButton popover component for detailed field documentation - Add info buttons to Environment.tsx RF propagation panels - VOLTAGE_MAP and getVoltageApprox helper for Li-ion voltage lookup Researched defaults and descriptions include: - Li-ion voltage curve (4.20V=100%, 3.60V=30%, 3.50V=15%, 3.40V=7%) - LoRa channel utilization (firmware throttles at 25%, issues at 50%) - Packet flood detection (normal 1-5/min, suspicious >10/min) - NWS severity levels with actionable descriptions - Tropospheric ducting M-units/km refractivity gradients - NOAA Space Weather R/S/G scales Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
9eb40b597c
commit
9369bd684f
2 changed files with 1085 additions and 175 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +1,4 @@
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState, useRef } from 'react'
|
||||||
import {
|
import {
|
||||||
Cloud,
|
Cloud,
|
||||||
Sun,
|
Sun,
|
||||||
|
|
@ -10,7 +10,42 @@ import {
|
||||||
Wind,
|
Wind,
|
||||||
Flame,
|
Flame,
|
||||||
Mountain,
|
Mountain,
|
||||||
|
HelpCircle,
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
|
|
||||||
|
// Info button component with popover
|
||||||
|
function InfoButton({ info }: { info: string }) {
|
||||||
|
const [show, setShow] = useState(false)
|
||||||
|
const ref = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function handleClickOutside(e: MouseEvent) {
|
||||||
|
if (ref.current && !ref.current.contains(e.target as Node)) {
|
||||||
|
setShow(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.addEventListener('mousedown', handleClickOutside)
|
||||||
|
return () => document.removeEventListener('mousedown', handleClickOutside)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative inline-block" ref={ref}>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setShow(!show)}
|
||||||
|
className="ml-1 text-slate-500 hover:text-slate-300 transition-colors"
|
||||||
|
aria-label="More information"
|
||||||
|
>
|
||||||
|
<HelpCircle size={14} />
|
||||||
|
</button>
|
||||||
|
{show && (
|
||||||
|
<div className="absolute z-50 left-0 mt-1 w-64 p-3 bg-[#1a1f2e] border border-[#2a3548] rounded-lg shadow-xl text-xs text-slate-300 leading-relaxed">
|
||||||
|
{info}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
import {
|
import {
|
||||||
fetchEnvStatus,
|
fetchEnvStatus,
|
||||||
fetchEnvActive,
|
fetchEnvActive,
|
||||||
|
|
@ -150,6 +185,7 @@ function SolarIndicesPanel({ swpc }: { swpc: SWPCStatus | null }) {
|
||||||
<h2 className="text-sm font-medium text-slate-400 mb-4 flex items-center gap-2">
|
<h2 className="text-sm font-medium text-slate-400 mb-4 flex items-center gap-2">
|
||||||
<Sun size={14} />
|
<Sun size={14} />
|
||||||
Solar/Geomagnetic Indices
|
Solar/Geomagnetic Indices
|
||||||
|
<InfoButton info="Space weather data from NOAA SWPC. Solar Flux Index (SFI) indicates HF propagation quality. Kp index measures geomagnetic disturbance. Higher values can degrade or enhance radio propagation." />
|
||||||
</h2>
|
</h2>
|
||||||
<div className="text-slate-500">Data not available</div>
|
<div className="text-slate-500">Data not available</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -176,12 +212,16 @@ function SolarIndicesPanel({ swpc }: { swpc: SWPCStatus | null }) {
|
||||||
<h2 className="text-sm font-medium text-slate-400 mb-4 flex items-center gap-2">
|
<h2 className="text-sm font-medium text-slate-400 mb-4 flex items-center gap-2">
|
||||||
<Sun size={14} />
|
<Sun size={14} />
|
||||||
Solar/Geomagnetic Indices
|
Solar/Geomagnetic Indices
|
||||||
|
<InfoButton info="Space weather data from NOAA SWPC. Solar Flux Index (SFI) indicates HF propagation quality (higher=better). Kp index measures geomagnetic disturbance (lower=better). R/S/G scales: R=Radio Blackout, S=Solar Radiation, G=Geomagnetic Storm." />
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-4 mb-4">
|
<div className="grid grid-cols-2 gap-4 mb-4">
|
||||||
{/* SFI */}
|
{/* SFI */}
|
||||||
<div className="bg-bg-hover rounded-lg p-3">
|
<div className="bg-bg-hover rounded-lg p-3">
|
||||||
<div className="text-xs text-slate-500 mb-1">Solar Flux Index</div>
|
<div className="text-xs text-slate-500 mb-1 flex items-center">
|
||||||
|
Solar Flux Index
|
||||||
|
<InfoButton info="10.7cm solar radio flux. <70=poor HF, 70-90=fair, 90-120=good, 120-150=very good, >150=excellent. Measured daily at noon UTC." />
|
||||||
|
</div>
|
||||||
<div className="text-2xl font-mono text-slate-100">
|
<div className="text-2xl font-mono text-slate-100">
|
||||||
{swpc.sfi?.toFixed(0) ?? '—'}
|
{swpc.sfi?.toFixed(0) ?? '—'}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -190,7 +230,10 @@ function SolarIndicesPanel({ swpc }: { swpc: SWPCStatus | null }) {
|
||||||
|
|
||||||
{/* Kp */}
|
{/* Kp */}
|
||||||
<div className="bg-bg-hover rounded-lg p-3">
|
<div className="bg-bg-hover rounded-lg p-3">
|
||||||
<div className="text-xs text-slate-500 mb-1">Planetary K-Index</div>
|
<div className="text-xs text-slate-500 mb-1 flex items-center">
|
||||||
|
Planetary K-Index
|
||||||
|
<InfoButton info="Geomagnetic disturbance scale 0-9. Kp 0-2=quiet, 3-4=unsettled, 5=minor storm (G1), 6=moderate (G2), 7=strong (G3), 8=severe (G4), 9=extreme (G5). Higher Kp degrades HF at high latitudes." />
|
||||||
|
</div>
|
||||||
<div className={`text-2xl font-mono ${getKpColor(swpc.kp_current)}`}>
|
<div className={`text-2xl font-mono ${getKpColor(swpc.kp_current)}`}>
|
||||||
{swpc.kp_current?.toFixed(1) ?? '—'}
|
{swpc.kp_current?.toFixed(1) ?? '—'}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -251,6 +294,7 @@ function DuctingPanel({ ducting }: { ducting: DuctingStatus | null }) {
|
||||||
<h2 className="text-sm font-medium text-slate-400 mb-4 flex items-center gap-2">
|
<h2 className="text-sm font-medium text-slate-400 mb-4 flex items-center gap-2">
|
||||||
<Wind size={14} />
|
<Wind size={14} />
|
||||||
Tropospheric Ducting
|
Tropospheric Ducting
|
||||||
|
<InfoButton info="Atmospheric conditions that trap VHF/UHF signals, allowing propagation far beyond normal line-of-sight. Measured as refractivity gradient (dM/dz) in M-units/km. Negative values indicate ducting." />
|
||||||
</h2>
|
</h2>
|
||||||
<div className="text-slate-500">Data not available</div>
|
<div className="text-slate-500">Data not available</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -281,11 +325,15 @@ function DuctingPanel({ ducting }: { ducting: DuctingStatus | null }) {
|
||||||
<h2 className="text-sm font-medium text-slate-400 mb-4 flex items-center gap-2">
|
<h2 className="text-sm font-medium text-slate-400 mb-4 flex items-center gap-2">
|
||||||
<Wind size={14} />
|
<Wind size={14} />
|
||||||
Tropospheric Ducting
|
Tropospheric Ducting
|
||||||
|
<InfoButton info="Atmospheric conditions that trap VHF/UHF signals, allowing propagation far beyond normal line-of-sight. Ducting can extend 900 MHz Meshtastic range significantly. Surface ducts form near the ground; elevated ducts form aloft." />
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{/* Condition */}
|
{/* Condition */}
|
||||||
<div className="bg-bg-hover rounded-lg p-4 mb-4">
|
<div className="bg-bg-hover rounded-lg p-4 mb-4">
|
||||||
<div className="text-xs text-slate-500 mb-1">Condition</div>
|
<div className="text-xs text-slate-500 mb-1 flex items-center">
|
||||||
|
Condition
|
||||||
|
<InfoButton info="Normal: Standard refraction. Super-refraction: Signals bend more than normal, slightly extended range. Ducting: Signals trapped in atmospheric layer, significantly extended range possible." />
|
||||||
|
</div>
|
||||||
<div className={`text-xl font-medium ${getConditionColor(ducting.condition)}`}>
|
<div className={`text-xl font-medium ${getConditionColor(ducting.condition)}`}>
|
||||||
{formatCondition(ducting.condition)}
|
{formatCondition(ducting.condition)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue