feat: upload to external services clublog qrz
This commit is contained in:
+37
-4
@@ -35,7 +35,7 @@ import { BandMap } from '@/components/BandMap';
|
||||
import { RecentQSOsGrid } from '@/components/RecentQSOsGrid';
|
||||
import { ShutdownProgress } from '@/components/ShutdownProgress';
|
||||
import { ClusterGrid } from '@/components/ClusterGrid';
|
||||
import { cleanSpotter, inferSpotMode, spotStatusKey } from '@/lib/spot';
|
||||
import { cleanSpotter, inferSpotMode, spotModeCategory, spotStatusKey } from '@/lib/spot';
|
||||
import { WorkedBeforeGrid } from '@/components/WorkedBeforeGrid';
|
||||
import { DetailsPanel, type DetailsState } from '@/components/DetailsPanel';
|
||||
|
||||
@@ -426,6 +426,10 @@ export default function App() {
|
||||
// already-worked). Otherwise only matching spots pass.
|
||||
type SpotStatusKey = 'new' | 'new-band' | 'new-slot' | 'worked';
|
||||
const [clusterStatusFilter, setClusterStatusFilter] = useState<Set<SpotStatusKey>>(new Set());
|
||||
// Mode filter chips. Empty set = show every mode. Categories map the
|
||||
// inferred per-spot mode onto SSB (phone) / CW / DATA (digital).
|
||||
type SpotModeCat = 'SSB' | 'CW' | 'DATA';
|
||||
const [clusterModeFilter, setClusterModeFilter] = useState<Set<SpotModeCat>>(new Set());
|
||||
const [clusterSearch, setClusterSearch] = useState('');
|
||||
const [showBandMap, setShowBandMap] = useState(false);
|
||||
type SortKey = 'time' | 'call' | 'freq' | 'band' | 'mode' | 'spotter' | 'source';
|
||||
@@ -1279,8 +1283,7 @@ export default function App() {
|
||||
className="font-mono text-base font-bold tracking-wider uppercase h-9 bg-muted/40 focus:bg-card"
|
||||
value={callsign}
|
||||
onChange={(e) => onCallsignInput(e.target.value)}
|
||||
placeholder="F4XYZ"
|
||||
/>
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col w-24">
|
||||
<Label className="mb-1 h-3.5 flex items-center gap-1">Band <LockBtn k="band" title="band" /></Label>
|
||||
@@ -1443,7 +1446,7 @@ export default function App() {
|
||||
<Input value={comment} onChange={(e) => setComment(e.target.value)} />
|
||||
</div>
|
||||
{!compact && (
|
||||
<div className="flex flex-col flex-1 min-w-[120px]"><Label className="mb-1 h-3.5">Note (ADIF)</Label>
|
||||
<div className="flex flex-col flex-1 min-w-[120px]"><Label className="mb-1 h-3.5">Note</Label>
|
||||
<Input value={note} onChange={(e) => setNote(e.target.value)} />
|
||||
</div>
|
||||
)}
|
||||
@@ -1777,6 +1780,32 @@ export default function App() {
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
<div className="w-px h-4 bg-border mx-1" />
|
||||
<span className="text-muted-foreground">Mode:</span>
|
||||
{([
|
||||
{ k: 'SSB' as SpotModeCat, label: 'SSB', cls: 'bg-sky-100 text-sky-800 border-sky-300' },
|
||||
{ k: 'CW' as SpotModeCat, label: 'CW', cls: 'bg-violet-100 text-violet-800 border-violet-300' },
|
||||
{ k: 'DATA' as SpotModeCat, label: 'DATA', cls: 'bg-emerald-100 text-emerald-800 border-emerald-300' },
|
||||
]).map((s) => {
|
||||
const on = clusterModeFilter.has(s.k);
|
||||
return (
|
||||
<button
|
||||
key={s.k}
|
||||
type="button"
|
||||
onClick={() => setClusterModeFilter((cur) => {
|
||||
const n = new Set(cur);
|
||||
if (n.has(s.k)) n.delete(s.k); else n.add(s.k);
|
||||
return n;
|
||||
})}
|
||||
className={cn(
|
||||
'px-1.5 py-0.5 rounded border text-[10px] font-bold tracking-wider transition-opacity',
|
||||
on ? s.cls : `${s.cls} opacity-40 hover:opacity-100`,
|
||||
)}
|
||||
>
|
||||
{s.label}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
<div className="flex-1" />
|
||||
<label className="flex items-center gap-1.5 text-xs cursor-pointer">
|
||||
<Checkbox checked={clusterGroup} onCheckedChange={(c) => setClusterGroup(!!c)} />
|
||||
@@ -1808,6 +1837,10 @@ export default function App() {
|
||||
const spotMode = inferSpotMode(s.comment ?? '', s.freq_hz);
|
||||
if (spotMode && mode && spotMode !== mode) return false;
|
||||
}
|
||||
if (clusterModeFilter.size > 0) {
|
||||
const cat = spotModeCategory(inferSpotMode(s.comment ?? '', s.freq_hz));
|
||||
if (!cat || !clusterModeFilter.has(cat)) return false;
|
||||
}
|
||||
if (clusterStatusFilter.size > 0) {
|
||||
const k = spotStatusKey(s.dx_call, s.band ?? '', s.comment ?? '', s.freq_hz);
|
||||
const st = spotStatus[k]?.status || '';
|
||||
|
||||
Reference in New Issue
Block a user