Files
paragliding/frontend/components/weather/threshold-controls.tsx
2026-01-03 14:16:16 -08:00

123 lines
3.9 KiB
TypeScript

'use client'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Slider } from '@/components/ui/slider'
import { CompassSelector } from '@/components/ui/compass-selector'
import { useThresholdStore } from '@/store/threshold-store'
import { useEffect } from 'react'
interface ThresholdControlsProps {
className?: string
}
export function ThresholdControls({ className }: ThresholdControlsProps) {
const {
speedMin,
speedMax,
dirCenter,
dirRange,
setSpeedRange,
setDirCenter,
setDirRange,
initFromURL,
} = useThresholdStore()
// Initialize from URL on mount
useEffect(() => {
initFromURL()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return (
<Card className={className}>
<CardHeader>
<CardTitle>Threshold Controls</CardTitle>
</CardHeader>
<CardContent className="space-y-8">
{/* Wind Speed Range */}
<div className="space-y-4">
<div>
<div className="mb-2">
<label className="text-sm font-medium">Wind Speed Range</label>
</div>
<div className="relative">
<Slider
value={[speedMin, speedMax]}
onValueChange={(values) => setSpeedRange(values[0], values[1])}
min={0}
max={30}
step={0.5}
minStepsBetweenThumbs={1}
className="min-h-[44px] py-4"
aria-label="Wind speed range threshold"
/>
<div className="flex justify-between text-xs font-medium mt-1">
<span style={{ position: 'absolute', left: `${(speedMin / 30) * 100}%`, transform: 'translateX(-50%)' }}>
{speedMin} mph
</span>
<span style={{ position: 'absolute', left: `${(speedMax / 30) * 100}%`, transform: 'translateX(-50%)' }}>
{speedMax} mph
</span>
</div>
</div>
</div>
</div>
{/* Wind Direction Center */}
<div className="space-y-4">
<div>
<div className="mb-4">
<label className="text-sm font-medium">Direction Center</label>
</div>
<div className="flex justify-center">
<CompassSelector
value={dirCenter}
onChange={setDirCenter}
range={dirRange}
size={220}
/>
</div>
</div>
</div>
{/* Wind Direction Range */}
<div className="space-y-4">
<div>
<div className="flex items-center justify-between mb-2">
<label className="text-sm font-medium">Direction Range</label>
<span className="text-sm text-muted-foreground">
±{dirRange}°
</span>
</div>
<Slider
value={[dirRange]}
onValueChange={(values) => setDirRange(values[0])}
min={5}
max={90}
step={5}
className="min-h-[44px] py-4"
aria-label="Wind direction range threshold"
/>
<div className="text-xs text-muted-foreground mt-1">
Acceptable range: {(dirCenter - dirRange + 360) % 360}° to {(dirCenter + dirRange) % 360}°
</div>
</div>
</div>
<div className="pt-4 border-t">
<p className="text-xs text-muted-foreground">
Thresholds are saved to URL and applied to charts automatically.
</p>
</div>
</CardContent>
</Card>
)
}
// Helper function to convert degrees to compass direction
function getCompassDirection(degrees: number): string {
const directions = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW']
const index = Math.round(degrees / 22.5) % 16
return directions[index]
}