chore: release v0.23.2

This commit is contained in:
2026-08-02 23:51:46 +02:00
parent 3da1d71323
commit 9846354bf9
18 changed files with 514 additions and 24 deletions
+39 -3
View File
@@ -1,7 +1,8 @@
import { useMemo } from 'react';
import { Star, Radio } from 'lucide-react';
import { Star, Radio, Sunrise, Sunset } from 'lucide-react';
import { Badge } from '@/components/ui/badge';
import { cn } from '@/lib/utils';
import { sunTimes } from '@/lib/sun';
import type { WorkedBeforeView } from '@/types';
type WorkedBefore = WorkedBeforeView;
@@ -13,6 +14,10 @@ interface Props {
currentMode: string;
bands?: string[]; // operator's configured bands; falls back to DEFAULT_BANDS
hasCall?: boolean; // a callsign is being entered — only then highlight the "current entry" cell
// DX station coordinates, for its sunrise/sunset. Optional: many spots resolve
// to an entity with no position at all, and the block simply does not appear.
lat?: number;
lon?: number;
}
// Compact column label for a band tag: keep the classic V/U for 2m/70cm,
@@ -84,7 +89,7 @@ function cellTitle(band: string, cls: string, status: string, current: boolean):
return `${band} ${cls}: ${desc}${current ? ' — current entry' : ''}`;
}
export function BandSlotGrid({ wb, busy, currentBand, currentMode, bands, hasCall = true }: Props) {
export function BandSlotGrid({ wb, busy, currentBand, currentMode, bands, hasCall = true, lat, lon }: Props) {
// Columns from the operator's configured bands (so the matrix shows only the
// bands they actually use), falling back to the built-in default set.
const cols = useMemo(
@@ -151,6 +156,36 @@ export function BandSlotGrid({ wb, busy, currentBand, currentMode, bands, hasCal
</Badge>
) : null;
// Sunrise / sunset AT THE DX, in UTC. A glance tells you whether the path is
// about to open or close on their side, which is the reason to look at a DX
// station's grey line at all. Recomputed only when the position changes.
const sun = useMemo(
() => (lat == null || lon == null ? null : sunTimes(new Date(), lat, lon)),
[lat, lon],
);
const sunBlock = sun ? (
<div className="ml-auto flex items-center gap-3 text-xs shrink-0"
title="Sunrise / sunset at the DX station (UTC)">
{sun.polarDay ? (
<span className="font-semibold text-warning">midnight sun</span>
) : sun.polarNight ? (
<span className="font-semibold text-info">polar night</span>
) : (
<>
<span className="flex items-center gap-1">
<Sunrise className="size-3.5 text-warning" />
<span className="font-mono tabular-nums">{sun.rise || '—'}</span>
</span>
<span className="flex items-center gap-1">
<Sunset className="size-3.5 text-info" />
<span className="font-mono tabular-nums">{sun.set || '—'}</span>
</span>
<span className="text-muted-foreground">UTC</span>
</>
)}
</div>
) : null;
return (
<section
className={cn(
@@ -158,7 +193,7 @@ export function BandSlotGrid({ wb, busy, currentBand, currentMode, bands, hasCal
newOne && 'bg-gradient-to-br from-warning-muted to-warning-muted rounded-lg',
)}
>
<div className="flex items-center gap-2 min-w-[220px]">
<div className="flex items-center gap-2 min-w-[220px] flex-1">
{newOne ? (
<>
<Badge className="bg-warning text-warning-foreground gap-1 px-3 py-1 text-[11px]">
@@ -207,6 +242,7 @@ export function BandSlotGrid({ wb, busy, currentBand, currentMode, bands, hasCal
Type a callsign to see entity stats
</span>
)}
{sunBlock}
</div>
<div className="flex flex-col gap-2">