// Two operator options that change how a spot LOOKS, shared by the DX-cluster // list and the band map so the two panels can never disagree about the same // spot — the lesson already learnt with the marker colours. // // muteWorked — a station already worked gets no colour and no badge. It // stays in the list, it simply stops competing for attention. // slotHighlight — a callsign not yet worked on THIS band and mode is coloured, // whatever the entity says. For an operator filling slots, a // common entity on a new band+mode is the whole point, and the // entity-level status calls it "worked". // // They compose deliberately: mute what is done, light up what is not. export type SpotDisplayOptions = { muteWorked: boolean; slotHighlight: boolean }; export function readSpotDisplayOptions(): SpotDisplayOptions { try { return { muteWorked: localStorage.getItem('opslog.clusterMuteWorked') === '1', slotHighlight: localStorage.getItem('opslog.clusterSlotHighlight') === '1', }; } catch { return { muteWorked: false, slotHighlight: false }; } } type Entry = { status?: string; worked_call?: boolean; worked_slot?: boolean; new_county?: boolean; new_pota?: boolean; new_pfx?: boolean; new_grid?: boolean; } | undefined; // applySpotDisplay rewrites a status entry per the options, so every consumer — // colour, badge, status text — follows from one decision instead of each panel // re-deriving it. export function applySpotDisplay(s: T, o: SpotDisplayOptions): T { if (!s) return s; let e = s; // Slot promotion runs first: a callsign not yet worked on this band and mode // is not done, whatever the entity says, so it earns a status before the mute // below can take its colour away. if (o.slotHighlight && e.worked_slot === false && (!e.status || e.status === 'worked')) { e = { ...e, status: 'new-call' } as NonNullable; } // Mute drops the blue already-worked-callsign mark, and NOTHING else. // // It used to blank the status as well, on the theory that a spot bringing no // novelty should stop painting entirely. That was wrong twice over. The status // is what the cluster list reads to DIM a row, so blanking it turned every // quiet grey row bright white — the option made the list louder, not quieter. // And an empty status means "entity not resolved" everywhere else, so muted // spots had to carry a flag saying they did not really mean that. // // Leaving the status alone costs nothing: a worked entity already renders with // no colour and gets dimmed, so removing the blue is the entire job. if (o.muteWorked) { e = { ...e, worked_call: false } as NonNullable; } return e; }