feat(appearance): give the worked-with-this-call dot its own two colours
The dot is drawn over all five cell backgrounds, so it cannot borrow one of their colours; it defaults to the theme foreground with a background ring and now takes two overrides of its own, worked and confirmed, alongside the rest of the matrix palette.
This commit is contained in:
@@ -174,6 +174,11 @@ type MatrixColors struct {
|
|||||||
EntityWorked string `json:"entity_worked"`
|
EntityWorked string `json:"entity_worked"`
|
||||||
NotWorked string `json:"not_worked"`
|
NotWorked string `json:"not_worked"`
|
||||||
CurrentEntry string `json:"current_entry"`
|
CurrentEntry string `json:"current_entry"`
|
||||||
|
// The dot marking a slot already worked with the callsign in hand. It is a
|
||||||
|
// mark rather than a background, so it needs its own two colours: it is
|
||||||
|
// drawn on top of all five of the above and must stay legible over each.
|
||||||
|
MarkWorked string `json:"mark_worked"`
|
||||||
|
MarkConfirmed string `json:"mark_confirmed"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// normMatrixColors keeps only plain hex values. Anything else becomes "" — i.e.
|
// normMatrixColors keeps only plain hex values. Anything else becomes "" — i.e.
|
||||||
@@ -196,6 +201,8 @@ func normMatrixColors(c MatrixColors) MatrixColors {
|
|||||||
EntityWorked: clean(c.EntityWorked),
|
EntityWorked: clean(c.EntityWorked),
|
||||||
NotWorked: clean(c.NotWorked),
|
NotWorked: clean(c.NotWorked),
|
||||||
CurrentEntry: clean(c.CurrentEntry),
|
CurrentEntry: clean(c.CurrentEntry),
|
||||||
|
MarkWorked: clean(c.MarkWorked),
|
||||||
|
MarkConfirmed: clean(c.MarkConfirmed),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -4,11 +4,11 @@
|
|||||||
"date": "",
|
"date": "",
|
||||||
"en": [
|
"en": [
|
||||||
"Each radio carries its own MY_RIG (Settings → CAT), written on every QSO made with it — ahead of the per-band station in Operating conditions, which says what you planned to use rather than which radio is keying. Left empty, nothing changes.",
|
"Each radio carries its own MY_RIG (Settings → CAT), written on every QSO made with it — ahead of the per-band station in Operating conditions, which says what you planned to use rather than which radio is keying. Left empty, nothing changes.",
|
||||||
"Worked-before matrix: a dot in the corner of a cell now means the callsign you are working has already been worked on that slot, whatever colour the entity status gave the cell."
|
"Worked-before matrix: a dot in the corner of a cell now means the callsign you are working has already been worked on that slot, whatever colour the entity status gave the cell. Its two colours (worked / confirmed with this callsign) are in Appearance with the other matrix colours."
|
||||||
],
|
],
|
||||||
"fr": [
|
"fr": [
|
||||||
"Chaque radio porte son propre MY_RIG (Réglages → CAT), inscrit sur chaque QSO fait avec elle — avant la station par bande des Conditions de trafic, qui dit ce qui était prévu et non quelle radio émet. Laissé vide, rien ne change.",
|
"Chaque radio porte son propre MY_RIG (Réglages → CAT), inscrit sur chaque QSO fait avec elle — avant la station par bande des Conditions de trafic, qui dit ce qui était prévu et non quelle radio émet. Laissé vide, rien ne change.",
|
||||||
"Matrice des contacts : un point dans le coin d'une case indique que l'indicatif en cours a déjà été contacté sur ce créneau, quelle que soit la couleur donnée par le statut de l'entité."
|
"Matrice des contacts : un point dans le coin d'une case indique que l'indicatif en cours a déjà été contacté sur ce créneau, quelle que soit la couleur donnée par le statut de l'entité. Ses deux couleurs (contacté / confirmé avec cet indicatif) se règlent dans Apparence avec les autres couleurs de la matrice."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -127,6 +127,12 @@ function MatrixColorsSection() {
|
|||||||
<span className="inline-block w-7 h-5 rounded bg-mx-dx-work" />
|
<span className="inline-block w-7 h-5 rounded bg-mx-dx-work" />
|
||||||
<span className="inline-block w-7 h-5 rounded bg-mx-none" />
|
<span className="inline-block w-7 h-5 rounded bg-mx-none" />
|
||||||
<span className="inline-block w-7 h-5 rounded bg-mx-none ring-2 ring-mx-cur ring-inset" />
|
<span className="inline-block w-7 h-5 rounded bg-mx-none ring-2 ring-mx-cur ring-inset" />
|
||||||
|
<span className="relative inline-block w-7 h-5 rounded bg-mx-dx-conf">
|
||||||
|
<span className="absolute top-[4px] right-[4px] size-[5px] rounded-full bg-mx-mark-work ring-1 ring-background" />
|
||||||
|
</span>
|
||||||
|
<span className="relative inline-block w-7 h-5 rounded bg-mx-dx-conf">
|
||||||
|
<span className="absolute top-[4px] right-[4px] size-[5px] rounded-full bg-mx-mark-conf ring-1 ring-background" />
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button" onClick={reset}
|
<button type="button" onClick={reset}
|
||||||
|
|||||||
@@ -81,26 +81,32 @@ const STATUS_CLASSES: Record<string, string> = {
|
|||||||
// i18n keys the Appearance panel's colour pickers use, so the two can never
|
// i18n keys the Appearance panel's colour pickers use, so the two can never
|
||||||
// disagree about which green is which. swatch = the background class (or a
|
// disagree about which green is which. swatch = the background class (or a
|
||||||
// special ring marker for the current-entry cell).
|
// special ring marker for the current-entry cell).
|
||||||
const LEGEND: { swatch: string; ring?: boolean; mark?: boolean; label: string }[] = [
|
const LEGEND: { swatch: string; ring?: boolean; mark?: string; label: string }[] = [
|
||||||
{ swatch: 'bg-mx-call-conf', label: 'mx.callConf' },
|
{ swatch: 'bg-mx-call-conf', label: 'mx.callConf' },
|
||||||
{ swatch: 'bg-mx-call-work', label: 'mx.callWork' },
|
{ swatch: 'bg-mx-call-work', label: 'mx.callWork' },
|
||||||
{ swatch: 'bg-mx-dx-conf', label: 'mx.dxConf' },
|
{ swatch: 'bg-mx-dx-conf', label: 'mx.dxConf' },
|
||||||
{ swatch: 'bg-mx-dx-work', label: 'mx.dxWork' },
|
{ swatch: 'bg-mx-dx-work', label: 'mx.dxWork' },
|
||||||
{ swatch: 'bg-mx-none', label: 'mx.none' },
|
{ swatch: 'bg-mx-none', label: 'mx.none' },
|
||||||
{ swatch: 'bg-mx-none', ring: true, label: 'mx.current' },
|
{ swatch: 'bg-mx-none', ring: true, label: 'mx.current' },
|
||||||
{ swatch: 'bg-mx-none', mark: true, label: 'mx.thisCall' },
|
{ swatch: 'bg-mx-none', mark: 'w', label: 'mx.markWork' },
|
||||||
|
{ swatch: 'bg-mx-none', mark: 'c', label: 'mx.markConf' },
|
||||||
];
|
];
|
||||||
|
|
||||||
// CallMark — "this callsign has already been worked on this slot".
|
// CallMark — "this callsign has already been worked on this slot".
|
||||||
//
|
//
|
||||||
// Drawn exactly the same way on every cell, whatever colour the entity status
|
// Drawn the same way on every cell, whatever colour the entity status gave it:
|
||||||
// gave it. That is the point: the operator learns one shape, and reads it
|
// the operator learns one shape and reads it without first working out what the
|
||||||
// without first working out what the background means. The dot is the theme
|
// background means. Only the fill changes, and only with the callsign's own
|
||||||
// foreground with a ring in the theme background, so it stays legible over all
|
// state (worked / confirmed) — never with the entity's. The ring is the theme
|
||||||
// five cell colours instead of needing a colour per case.
|
// background, which is what keeps the dot legible over all five cell colours.
|
||||||
function CallMark() {
|
function CallMark({ state = 'w' }: { state?: string }) {
|
||||||
return (
|
return (
|
||||||
<span className="pointer-events-none absolute top-[4px] right-[4px] size-[5px] rounded-full bg-foreground ring-1 ring-background" />
|
<span
|
||||||
|
className={cn(
|
||||||
|
'pointer-events-none absolute top-[4px] right-[4px] size-[5px] rounded-full ring-1 ring-background',
|
||||||
|
state === 'c' ? 'bg-mx-mark-conf' : 'bg-mx-mark-work',
|
||||||
|
)}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,7 +360,7 @@ export function BandSlotGrid({ wb, busy, currentBand, currentMode, bands, hasCal
|
|||||||
isCurrent && 'ring-2 ring-mx-cur ring-inset',
|
isCurrent && 'ring-2 ring-mx-cur ring-inset',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{mine ? <CallMark /> : null}
|
{mine ? <CallMark state={mine} /> : null}
|
||||||
</td>
|
</td>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -375,7 +381,7 @@ export function BandSlotGrid({ wb, busy, currentBand, currentMode, bands, hasCal
|
|||||||
l.ring && 'ring-2 ring-mx-cur ring-inset',
|
l.ring && 'ring-2 ring-mx-cur ring-inset',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{l.mark ? <CallMark /> : null}
|
{l.mark ? <CallMark state={l.mark} /> : null}
|
||||||
</span>
|
</span>
|
||||||
{t(l.label)}
|
{t(l.label)}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ const en: Dict = {
|
|||||||
'mx.tipCallConf': 'This callsign confirmed', 'mx.tipCallWork': 'This callsign worked (not confirmed)',
|
'mx.tipCallConf': 'This callsign confirmed', 'mx.tipCallWork': 'This callsign worked (not confirmed)',
|
||||||
'mx.tipDxConf': 'Entity confirmed (other callsign)', 'mx.tipDxWork': 'Entity worked (other callsign)',
|
'mx.tipDxConf': 'Entity confirmed (other callsign)', 'mx.tipDxWork': 'Entity worked (other callsign)',
|
||||||
'mx.tipNone': 'Never worked', 'mx.tipClick': 'click to list the QSOs',
|
'mx.tipNone': 'Never worked', 'mx.tipClick': 'click to list the QSOs',
|
||||||
'mx.thisCall': 'this callsign',
|
'mx.markWork': 'This callsign worked', 'mx.markConf': 'This callsign confirmed',
|
||||||
'mx.tipThisCall': 'already worked with this callsign',
|
'mx.tipThisCall': 'already worked with this callsign',
|
||||||
'mx.tipThisCallConf': 'already confirmed with this callsign',
|
'mx.tipThisCallConf': 'already confirmed with this callsign',
|
||||||
// FTx decodes panel (Tools -> FT decodes)
|
// FTx decodes panel (Tools -> FT decodes)
|
||||||
@@ -616,7 +616,7 @@ const fr: Dict = {
|
|||||||
'mx.tipCallConf': 'Cet indicatif est confirmé', 'mx.tipCallWork': 'Cet indicatif est contacté (non confirmé)',
|
'mx.tipCallConf': 'Cet indicatif est confirmé', 'mx.tipCallWork': 'Cet indicatif est contacté (non confirmé)',
|
||||||
'mx.tipDxConf': 'Entité confirmée (autre indicatif)', 'mx.tipDxWork': 'Entité contactée (autre indicatif)',
|
'mx.tipDxConf': 'Entité confirmée (autre indicatif)', 'mx.tipDxWork': 'Entité contactée (autre indicatif)',
|
||||||
'mx.tipNone': 'Jamais contacté', 'mx.tipClick': 'cliquer pour lister les QSO',
|
'mx.tipNone': 'Jamais contacté', 'mx.tipClick': 'cliquer pour lister les QSO',
|
||||||
'mx.thisCall': 'cet indicatif',
|
'mx.markWork': 'Cet indicatif contacté', 'mx.markConf': 'Cet indicatif confirmé',
|
||||||
'mx.tipThisCall': 'déjà contacté avec cet indicatif',
|
'mx.tipThisCall': 'déjà contacté avec cet indicatif',
|
||||||
'mx.tipThisCallConf': 'déjà confirmé avec cet indicatif',
|
'mx.tipThisCallConf': 'déjà confirmé avec cet indicatif',
|
||||||
// Panneau des decodes FTx (Outils -> Decodes FT)
|
// Panneau des decodes FTx (Outils -> Decodes FT)
|
||||||
|
|||||||
@@ -14,9 +14,11 @@ export type MatrixColors = {
|
|||||||
entity_worked: string;
|
entity_worked: string;
|
||||||
not_worked: string;
|
not_worked: string;
|
||||||
current_entry: string;
|
current_entry: string;
|
||||||
|
mark_worked: string;
|
||||||
|
mark_confirmed: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The six settings fields and the CSS custom property each one drives. Also the
|
// The settings fields and the CSS custom property each one drives. Also the
|
||||||
// display order — the same order the legend under the matrix reads in, so the
|
// display order — the same order the legend under the matrix reads in, so the
|
||||||
// settings panel and the grid can never disagree about which green is which.
|
// settings panel and the grid can never disagree about which green is which.
|
||||||
export const MATRIX_VARS: { key: keyof Omit<MatrixColors, 'enabled'>; cssVar: string; label: string }[] = [
|
export const MATRIX_VARS: { key: keyof Omit<MatrixColors, 'enabled'>; cssVar: string; label: string }[] = [
|
||||||
@@ -26,12 +28,15 @@ export const MATRIX_VARS: { key: keyof Omit<MatrixColors, 'enabled'>; cssVar: st
|
|||||||
{ key: 'entity_worked', cssVar: '--mx-dx-work', label: 'mx.dxWork' },
|
{ key: 'entity_worked', cssVar: '--mx-dx-work', label: 'mx.dxWork' },
|
||||||
{ key: 'not_worked', cssVar: '--mx-none', label: 'mx.none' },
|
{ key: 'not_worked', cssVar: '--mx-none', label: 'mx.none' },
|
||||||
{ key: 'current_entry', cssVar: '--mx-cur', label: 'mx.current' },
|
{ key: 'current_entry', cssVar: '--mx-cur', label: 'mx.current' },
|
||||||
|
{ key: 'mark_worked', cssVar: '--mx-mark-work', label: 'mx.markWork' },
|
||||||
|
{ key: 'mark_confirmed', cssVar: '--mx-mark-conf', label: 'mx.markConf' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const emptyMatrixColors = (): MatrixColors => ({
|
export const emptyMatrixColors = (): MatrixColors => ({
|
||||||
enabled: false,
|
enabled: false,
|
||||||
call_confirmed: '', call_worked: '', entity_confirmed: '',
|
call_confirmed: '', call_worked: '', entity_confirmed: '',
|
||||||
entity_worked: '', not_worked: '', current_entry: '',
|
entity_worked: '', not_worked: '', current_entry: '',
|
||||||
|
mark_worked: '', mark_confirmed: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
// applyMatrixColors stamps (or clears) the overrides on <html>. Safe to call as
|
// applyMatrixColors stamps (or clears) the overrides on <html>. Safe to call as
|
||||||
|
|||||||
@@ -91,6 +91,11 @@
|
|||||||
be recoloured on its own without dragging every other warning in the app
|
be recoloured on its own without dragging every other warning in the app
|
||||||
with it (Appearance → matrix colours). */
|
with it (Appearance → matrix colours). */
|
||||||
--mx-cur: var(--warning);
|
--mx-cur: var(--warning);
|
||||||
|
/* The "worked with this callsign" dot. Declared ONCE, like --mx-cur: it is
|
||||||
|
drawn over every one of the five cell colours, so it follows the theme's own
|
||||||
|
foreground/background pair rather than a per-theme colour of its own. */
|
||||||
|
--mx-mark-work: var(--foreground);
|
||||||
|
--mx-mark-conf: var(--foreground);
|
||||||
|
|
||||||
--scrollbar-thumb: #b8a880;
|
--scrollbar-thumb: #b8a880;
|
||||||
--scrollbar-thumb-hover: #968455;
|
--scrollbar-thumb-hover: #968455;
|
||||||
@@ -981,6 +986,8 @@
|
|||||||
--color-mx-dx-work: var(--mx-dx-work);
|
--color-mx-dx-work: var(--mx-dx-work);
|
||||||
--color-mx-none: var(--mx-none);
|
--color-mx-none: var(--mx-none);
|
||||||
--color-mx-cur: var(--mx-cur);
|
--color-mx-cur: var(--mx-cur);
|
||||||
|
--color-mx-mark-work: var(--mx-mark-work);
|
||||||
|
--color-mx-mark-conf: var(--mx-mark-conf);
|
||||||
|
|
||||||
--radius: 0.5rem;
|
--radius: 0.5rem;
|
||||||
|
|
||||||
|
|||||||
@@ -3066,6 +3066,8 @@ export namespace main {
|
|||||||
entity_worked: string;
|
entity_worked: string;
|
||||||
not_worked: string;
|
not_worked: string;
|
||||||
current_entry: string;
|
current_entry: string;
|
||||||
|
mark_worked: string;
|
||||||
|
mark_confirmed: string;
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
static createFrom(source: any = {}) {
|
||||||
return new MatrixColors(source);
|
return new MatrixColors(source);
|
||||||
@@ -3080,6 +3082,8 @@ export namespace main {
|
|||||||
this.entity_worked = source["entity_worked"];
|
this.entity_worked = source["entity_worked"];
|
||||||
this.not_worked = source["not_worked"];
|
this.not_worked = source["not_worked"];
|
||||||
this.current_entry = source["current_entry"];
|
this.current_entry = source["current_entry"];
|
||||||
|
this.mark_worked = source["mark_worked"];
|
||||||
|
this.mark_confirmed = source["mark_confirmed"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user