59 lines
2.3 KiB
TypeScript
59 lines
2.3 KiB
TypeScript
import { RSRP_LEGEND } from '@/constants/rsrp-thresholds.ts';
|
|
import { useCoverageStore } from '@/store/coverage.ts';
|
|
import { useSitesStore } from '@/store/sites.ts';
|
|
|
|
export default function Legend() {
|
|
const result = useCoverageStore((s) => s.result);
|
|
const heatmapVisible = useCoverageStore((s) => s.heatmapVisible);
|
|
const toggleHeatmap = useCoverageStore((s) => s.toggleHeatmap);
|
|
const settings = useCoverageStore((s) => s.settings);
|
|
const sites = useSitesStore((s) => s.sites);
|
|
|
|
if (!result) return null;
|
|
|
|
// Estimate coverage area: total points * resolution^2
|
|
const areaKm2 = (result.totalPoints * settings.resolution * settings.resolution) / 1e6;
|
|
|
|
return (
|
|
<div className="absolute bottom-6 right-2 z-[1000] bg-white dark:bg-dark-surface rounded-lg shadow-lg border border-gray-200 dark:border-dark-border p-3 min-w-[170px]">
|
|
{/* Header with toggle */}
|
|
<div className="flex items-center justify-between mb-2">
|
|
<h3 className="text-xs font-semibold text-gray-700 dark:text-dark-text">Signal (RSRP)</h3>
|
|
<button
|
|
onClick={toggleHeatmap}
|
|
className={`w-8 h-4 rounded-full transition-colors relative
|
|
${heatmapVisible ? 'bg-blue-500' : 'bg-gray-300 dark:bg-dark-border'}`}
|
|
>
|
|
<span
|
|
className={`absolute top-0.5 w-3 h-3 rounded-full bg-white shadow transition-transform
|
|
${heatmapVisible ? 'left-4' : 'left-0.5'}`}
|
|
/>
|
|
</button>
|
|
</div>
|
|
|
|
{/* Legend items */}
|
|
<div className="space-y-1">
|
|
{RSRP_LEGEND.map((item) => (
|
|
<div key={item.label} className="flex items-center gap-2">
|
|
<div
|
|
className="w-3 h-3 rounded-sm flex-shrink-0"
|
|
style={{ backgroundColor: item.color }}
|
|
/>
|
|
<span className="text-[10px] text-gray-600 dark:text-gray-400">
|
|
{item.label}: {item.range}
|
|
</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{/* Stats */}
|
|
<div className="mt-2 pt-2 border-t border-gray-100 dark:border-dark-border text-[10px] text-gray-400 dark:text-dark-muted space-y-0.5">
|
|
<div>Points: {result.totalPoints.toLocaleString()}</div>
|
|
<div>Time: {(result.calculationTime / 1000).toFixed(2)}s</div>
|
|
<div>Area: ~{areaKm2.toFixed(1)} km²</div>
|
|
<div>Sites: {sites.length}</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|