feat(sat): a wider frequency list, a resizable readout, one locator

Three things reported together from the tab.

The shipped frequency plan went from eleven satellites to twenty-five:
the eight Tevel FM cubesats, EO-88, AO-109, CAS-4A and 4B, TO-108,
GreenCube's single-frequency digipeater, and QO-100's wideband
transponder beside its narrowband one. It remains a starting point in a
file the operator can correct — a transponder gets switched and no
release should be needed to follow it — and the picker still lists every
bird in the element set when the "with a plan" filter is unticked.

The readout column drags to any width between 240 and 720 pixels,
double-clicks back to its default, and folds away entirely. How much map
against how much detail is the operator's call: watching a footprint
cross an ocean and working a pass want opposite things.

And the locator is no longer asked for twice. Passes are predicted from
the station locator, which is set once in Station information; the field
here was only ever for an antenna at another site, so it says so and sits
folded away. Nobody should have to wonder which of two locators is in
use.

Also: "Driven by" is two columns wide. "OpsLog (EasyComm II)" did not fit
in a third of the row, and a truncated choice is a choice that cannot be
read.
This commit is contained in:
2026-09-07 22:36:48 +02:00
parent 76022ff91c
commit b478cbfd2a
6 changed files with 388 additions and 33 deletions
+8 -2
View File
@@ -11,7 +11,10 @@
"One satellite list, in one place. Settings → Lists → Satellites is gone: the birds it held by hand had nothing to do with the ones the tracker knew, and the same station kept two lists that drifted apart. The SAT_NAME box on the entry form now offers the satellites you follow — plus anything the old list still held, so nobody's typing is lost. Satellites also moved out of Hardware, where it never belonged, and sits with Operating.", "One satellite list, in one place. Settings → Lists → Satellites is gone: the birds it held by hand had nothing to do with the ones the tracker knew, and the same station kept two lists that drifted apart. The SAT_NAME box on the entry form now offers the satellites you follow — plus anything the old list still held, so nobody's typing is lost. Satellites also moved out of Hardware, where it never belonged, and sits with Operating.",
"PstRotator can point the antenna for satellites too. It handles azimuth and elevation and already knows your controller, so if you run it, choose it in Settings → Satellites and OpsLog sends it the bearing instead of taking the cable itself — two programs on one controller is one too many. Its overlap handling stays its own: a 450° rotator is PstRotator's business, not something two programs should each decide about mid-pass.", "PstRotator can point the antenna for satellites too. It handles azimuth and elevation and already knows your controller, so if you run it, choose it in Settings → Satellites and OpsLog sends it the bearing instead of taking the cable itself — two programs on one controller is one too many. Its overlap handling stays its own: a 450° rotator is PstRotator's business, not something two programs should each decide about mid-pass.",
"Each map keeps its own imagery. The world map and the grid-square map shared one setting, so choosing satellite imagery to look at grids repainted the main map as well, and there was no way to have terrain on one and plain streets on the other. All four — world, grid squares, FT map, satellites — now remember their own choice, and it travels with the data folder like the remembered views. A choice already made for the grid map is carried over, not reset.", "Each map keeps its own imagery. The world map and the grid-square map shared one setting, so choosing satellite imagery to look at grids repainted the main map as well, and there was no way to have terrain on one and plain streets on the other. All four — world, grid squares, FT map, satellites — now remember their own choice, and it travels with the data folder like the remembered views. A choice already made for the grid map is carried over, not reset.",
"Two or three FT8 programs at once no longer fight over the callsign field. Click a station in MSHV and only MSHV has a DX Call; WSJT-X and JTDX beside it are idle and say so once a second each — and OpsLog was reading those as MSHV abandoning the station, so the entry emptied and refilled at 1 Hz and the map zoomed in and out with it. A cleared DX Call is now read per program, never across the listener; and the program that announces a station keeps the entry field until it clears its own call, is closed, or the QSO is logged." "Two or three FT8 programs at once no longer fight over the callsign field. Click a station in MSHV and only MSHV has a DX Call; WSJT-X and JTDX beside it are idle and say so once a second each — and OpsLog was reading those as MSHV abandoning the station, so the entry emptied and refilled at 1 Hz and the map zoomed in and out with it. A cleared DX Call is now read per program, never across the listener; and the program that announces a station keeps the entry field until it clears its own call, is closed, or the QSO is logged.",
"The satellite readout column can be resized, and hidden. Drag the grip between it and the map, double-click to reset it, or fold it away with the button in the header when the map is what you want to look at. The width and the choice are remembered and travel with the data folder.",
"Twenty-five satellites ship with a frequency plan instead of eleven: the eight Tevel FM cubesats, EO-88, AO-109, CAS-4A and 4B, TO-108, GreenCube's digipeater, and QO-100's wideband transponder beside its narrowband one. The list is still a starting point in a file you can correct — and the satellite picker will show every bird in the element set, plan or no plan, if you untick 'only those with a frequency plan'.",
"Satellites no longer asks for a locator you have already given. Passes are predicted from your station locator; the field is now folded away under 'the satellite antenna is at another site', which is the only case it was ever for."
], ],
"fr": [ "fr": [
"[NOUVEAU] Satellites. Un nouvel onglet (Outils → Satellites) suit les satellites amateurs : une carte avec l'empreinte de chacun et la trace au sol de celui qui est sélectionné, les prochains passages avec leur élévation maximale, et — pour le satellite en cours — l'azimut, l'élévation et les fréquences de descente et de montée corrigées de l'effet Doppler. Les éléments orbitaux viennent de Celestrak (avec un miroir derrière) et sont conservés sur disque : l'onglet est rempli dès son ouverture, même sans internet. Les éléments d'un satellite qu'aucun flux ne diffuse encore peuvent être collés à la main et survivent à chaque mise à jour. La liste de fréquences fournie couvre les satellites FM et linéaires ainsi que QO-100, dans un fichier que vous pouvez corriger vous-même quand un transpondeur change de mode.", "[NOUVEAU] Satellites. Un nouvel onglet (Outils → Satellites) suit les satellites amateurs : une carte avec l'empreinte de chacun et la trace au sol de celui qui est sélectionné, les prochains passages avec leur élévation maximale, et — pour le satellite en cours — l'azimut, l'élévation et les fréquences de descente et de montée corrigées de l'effet Doppler. Les éléments orbitaux viennent de Celestrak (avec un miroir derrière) et sont conservés sur disque : l'onglet est rempli dès son ouverture, même sans internet. Les éléments d'un satellite qu'aucun flux ne diffuse encore peuvent être collés à la main et survivent à chaque mise à jour. La liste de fréquences fournie couvre les satellites FM et linéaires ainsi que QO-100, dans un fichier que vous pouvez corriger vous-même quand un transpondeur change de mode.",
@@ -22,7 +25,10 @@
"Une seule liste de satellites, à un seul endroit. Réglages → Listes → Satellites disparaît : les satellites qu'on y saisissait à la main n'avaient aucun rapport avec ceux que connaissait le suivi, et une même station entretenait deux listes qui divergeaient. Le champ SAT_NAME de la saisie propose désormais les satellites que vous suivez — plus ce que l'ancienne liste contenait encore, pour ne rien perdre. Satellites quitte aussi Matériel, où il n'avait rien à faire, pour rejoindre Opération.", "Une seule liste de satellites, à un seul endroit. Réglages → Listes → Satellites disparaît : les satellites qu'on y saisissait à la main n'avaient aucun rapport avec ceux que connaissait le suivi, et une même station entretenait deux listes qui divergeaient. Le champ SAT_NAME de la saisie propose désormais les satellites que vous suivez — plus ce que l'ancienne liste contenait encore, pour ne rien perdre. Satellites quitte aussi Matériel, où il n'avait rien à faire, pour rejoindre Opération.",
"PstRotator peut aussi pointer l'antenne pour les satellites. Il gère azimut et élévation et connaît déjà votre contrôleur : si vous le faites tourner, choisissez-le dans Réglages → Satellites et OpsLog lui envoie le cap au lieu de prendre le câble lui-même — deux programmes sur un contrôleur, c'est un de trop. Le recouvrement reste son affaire : un rotor 450°, c'est à PstRotator d'en décider, pas à deux programmes en plein passage.", "PstRotator peut aussi pointer l'antenne pour les satellites. Il gère azimut et élévation et connaît déjà votre contrôleur : si vous le faites tourner, choisissez-le dans Réglages → Satellites et OpsLog lui envoie le cap au lieu de prendre le câble lui-même — deux programmes sur un contrôleur, c'est un de trop. Le recouvrement reste son affaire : un rotor 450°, c'est à PstRotator d'en décider, pas à deux programmes en plein passage.",
"Chaque carte garde son propre fond. La carte principale et celle des carrés partageaient un seul réglage : choisir la vue satellite pour regarder les carrés repeignait aussi la carte principale, et il n'y avait aucun moyen d'avoir le relief sur l'une et les rues sur l'autre. Les quatre — principale, carrés, FT map, satellites — retiennent désormais leur propre choix, qui suit le dossier de données comme les positions mémorisées. Un choix déjà fait pour la carte des carrés est repris, pas réinitialisé.", "Chaque carte garde son propre fond. La carte principale et celle des carrés partageaient un seul réglage : choisir la vue satellite pour regarder les carrés repeignait aussi la carte principale, et il n'y avait aucun moyen d'avoir le relief sur l'une et les rues sur l'autre. Les quatre — principale, carrés, FT map, satellites — retiennent désormais leur propre choix, qui suit le dossier de données comme les positions mémorisées. Un choix déjà fait pour la carte des carrés est repris, pas réinitialisé.",
"Deux ou trois logiciels FT8 en même temps ne se disputent plus le champ indicatif. Cliquez une station dans MSHV et lui seul a un DX Call ; WSJT-X et JTDX à côté sont au repos et le disent une fois par seconde chacun — et OpsLog y lisait MSHV abandonnant la station : le champ se vidait et se remplissait à 1 Hz, la carte zoomant au même rythme. Un DX Call effacé est désormais lu par programme, jamais à l'échelle du port ; et le logiciel qui annonce une station garde le champ jusqu'à ce qu'il efface son propre indicatif, soit fermé, ou que le QSO soit enregistré." "Deux ou trois logiciels FT8 en même temps ne se disputent plus le champ indicatif. Cliquez une station dans MSHV et lui seul a un DX Call ; WSJT-X et JTDX à côté sont au repos et le disent une fois par seconde chacun — et OpsLog y lisait MSHV abandonnant la station : le champ se vidait et se remplissait à 1 Hz, la carte zoomant au même rythme. Un DX Call effacé est désormais lu par programme, jamais à l'échelle du port ; et le logiciel qui annonce une station garde le champ jusqu'à ce qu'il efface son propre indicatif, soit fermé, ou que le QSO soit enregistré.",
"La colonne de droite de l'onglet Satellites se redimensionne et se masque. Tirez la poignée entre elle et la carte, double-cliquez pour la remettre par défaut, ou repliez-la avec le bouton de l'en-tête quand c'est la carte qui vous intéresse. La largeur et le choix sont mémorisés et suivent le dossier de données.",
"Vingt-cinq satellites livrés avec un plan de fréquences au lieu de onze : les huit cubesats FM Tevel, EO-88, AO-109, CAS-4A et 4B, TO-108, le digipeater de GreenCube, et le transpondeur large bande de QO-100 à côté de son bande étroite. La liste reste un point de départ, dans un fichier que vous pouvez corriger — et le sélecteur affiche tous les satellites du jeu d'éléments, avec plan ou non, si vous décochez « seulement ceux avec un plan de fréquences ».",
"Satellites ne redemande plus un locator déjà renseigné. Les passages sont calculés depuis le locator de votre station ; le champ est replié sous « l'antenne satellite est sur un autre site », le seul cas pour lequel il existait."
] ]
}, },
{ {
+64 -2
View File
@@ -1,7 +1,7 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import L from 'leaflet'; import L from 'leaflet';
import 'leaflet/dist/leaflet.css'; import 'leaflet/dist/leaflet.css';
import { Satellite as SatIcon, Radio, ArrowUp, ArrowDown } from 'lucide-react'; import { Satellite as SatIcon, Radio, ArrowUp, ArrowDown, PanelRightClose, PanelRightOpen } from 'lucide-react';
import { import {
GetSatelliteBirds, GetSatellitePositions, GetSatellitePasses, GetSatelliteTuning, GetSatelliteBirds, GetSatellitePositions, GetSatellitePasses, GetSatelliteTuning,
GetSatelliteGroundTrack, GetSatelliteTLEInfo, GetSatelliteNextPass, GetSatelliteGroundTrack, GetSatelliteTLEInfo, GetSatelliteNextPass,
@@ -13,6 +13,7 @@ import { gridToLatLon, splitAtAntimeridian } from '@/lib/maidenhead';
import { BASEMAPS, type BasemapKey } from '@/components/MainMap'; import { BASEMAPS, type BasemapKey } from '@/components/MainMap';
import { loadMapView, saveMapView } from '@/lib/mapView'; import { loadMapView, saveMapView } from '@/lib/mapView';
import { loadMapBase, saveMapBase, MAP_BASE_SAT } from '@/lib/mapBase'; import { loadMapBase, saveMapBase, MAP_BASE_SAT } from '@/lib/mapBase';
import { writeUiPref } from '@/lib/uiPref';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { useI18n } from '@/lib/i18n'; import { useI18n } from '@/lib/i18n';
@@ -63,6 +64,14 @@ type Track = {
const MAP_VIEW_SAT = 'opslog.satMapView'; const MAP_VIEW_SAT = 'opslog.satMapView';
// The readout column. Wide enough by default to hold a frequency to the hertz
// without wrapping, and adjustable because how much map an operator wants
// against how much detail is theirs to decide — a station watching a footprint
// cross an ocean wants the map, one working a pass wants the numbers.
const SIDE_W_KEY = 'opslog.satSideWidth';
const SIDE_SHOWN_KEY = 'opslog.satSideShown';
const SIDE_W_DEFAULT = 336, SIDE_W_MIN = 240, SIDE_W_MAX = 720;
const fmtHz = (hz: number) => { const fmtHz = (hz: number) => {
if (!hz) return '—'; if (!hz) return '—';
// Six decimals: a linear transponder is tuned to the hundred hertz, and the // Six decimals: a linear transponder is tuned to the hundred hertz, and the
@@ -253,6 +262,35 @@ export function SatellitePanel({ myGrid }: { myGrid: string }) {
const home = useMemo(() => gridToLatLon(myGrid), [myGrid]); const home = useMemo(() => gridToLatLon(myGrid), [myGrid]);
// ── The readout column ───────────────────────────────────────────────────
const [sideW, setSideW] = useState<number>(() => {
const n = parseFloat(localStorage.getItem(SIDE_W_KEY) || '');
return Number.isFinite(n) && n >= SIDE_W_MIN && n <= SIDE_W_MAX ? n : SIDE_W_DEFAULT;
});
const [sideShown, setSideShown] = useState(() => localStorage.getItem(SIDE_SHOWN_KEY) !== '0');
useEffect(() => { writeUiPref(SIDE_W_KEY, String(Math.round(sideW))); }, [sideW]);
useEffect(() => { writeUiPref(SIDE_SHOWN_KEY, sideShown ? '1' : '0'); }, [sideShown]);
// Dragging the grip. Measured from where the pointer STARTED rather than from
// the container, and with the pointer captured — without the capture the map
// underneath swallows the moves the instant the cursor crosses it.
const startSideDrag = (e: React.PointerEvent) => {
e.preventDefault();
(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
const x0 = e.clientX;
const w0 = sideW;
const onMove = (ev: PointerEvent) => {
setSideW(Math.min(SIDE_W_MAX, Math.max(SIDE_W_MIN, Math.round(w0 + (x0 - ev.clientX)))));
};
const onUp = () => {
window.removeEventListener('pointermove', onMove);
window.removeEventListener('pointerup', onUp);
};
window.addEventListener('pointermove', onMove);
window.addEventListener('pointerup', onUp);
};
useEffect(() => { useEffect(() => {
if (!divRef.current || mapRef.current) return; if (!divRef.current || mapRef.current) return;
const m = L.map(divRef.current, { const m = L.map(divRef.current, {
@@ -417,6 +455,16 @@ export function SatellitePanel({ myGrid }: { myGrid: string }) {
> >
{Object.entries(BASEMAPS).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)} {Object.entries(BASEMAPS).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)}
</select> </select>
{/* Put the whole window on the map. On a laptop the readout takes a
third of the screen, and there are moments — watching a footprint
cross an ocean — when the map IS the answer. */}
<Button
variant="ghost" size="sm" className="h-7 px-1.5"
onClick={() => setSideShown((v) => !v)}
title={sideShown ? t('sat.hideSide') : t('sat.showSide')}
>
{sideShown ? <PanelRightClose className="size-3.5" /> : <PanelRightOpen className="size-3.5" />}
</Button>
</div> </div>
{err && <div className="px-2 text-[11px] text-danger shrink-0">{err}</div>} {err && <div className="px-2 text-[11px] text-danger shrink-0">{err}</div>}
@@ -431,7 +479,21 @@ export function SatellitePanel({ myGrid }: { myGrid: string }) {
<div ref={divRef} className="h-full w-full" /> <div ref={divRef} className="h-full w-full" />
</div> </div>
<div className="w-[21rem] shrink-0 flex flex-col gap-1 min-h-0"> {sideShown && (
<div
role="separator"
aria-orientation="vertical"
title={t('sat.sideWidthTip')}
onPointerDown={startSideDrag}
onDoubleClick={() => setSideW(SIDE_W_DEFAULT)}
className="group relative shrink-0 w-2 cursor-col-resize flex items-center justify-center"
>
<span className="h-10 w-[3px] rounded-full bg-border group-hover:bg-primary transition-colors" />
</div>
)}
<div className={cn('shrink-0 flex flex-col gap-1 min-h-0', !sideShown && 'hidden')}
style={{ width: sideW }}>
{/* The pass. The first thing an operator looks at and the reason they {/* The pass. The first thing an operator looks at and the reason they
sit down: how long have I got, and how high does it get. */} sit down: how long have I got, and how high does it get. */}
<div className={cn('rounded-lg border bg-card p-2', <div className={cn('rounded-lg border bg-card p-2',
+21 -11
View File
@@ -4531,11 +4531,6 @@ function SettingsModalImpl({ onClose, onSaved, initialSection, onMainPaneChanged
</div> </div>
<div className="space-y-5 max-w-xl"> <div className="space-y-5 max-w-xl">
<div className="grid grid-cols-3 gap-3"> <div className="grid grid-cols-3 gap-3">
<div className="space-y-1">
<Label>{t('satset.grid')}</Label>
<Input className="font-mono" placeholder={t('satset.gridPlaceholder')}
value={satCfg.grid ?? ''} onChange={(e) => set('grid', e.target.value.toUpperCase())} />
</div>
<div className="space-y-1"> <div className="space-y-1">
<Label>{t('satset.altM')}</Label> <Label>{t('satset.altM')}</Label>
<Input className="font-mono" value={String(satCfg.alt_m ?? 0)} <Input className="font-mono" value={String(satCfg.alt_m ?? 0)}
@@ -4546,16 +4541,28 @@ function SettingsModalImpl({ onClose, onSaved, initialSection, onMainPaneChanged
<Input className="font-mono" value={String(satCfg.min_el ?? 10)} <Input className="font-mono" value={String(satCfg.min_el ?? 10)}
onChange={(e) => set('min_el', num(e.target.value))} /> onChange={(e) => set('min_el', num(e.target.value))} />
</div> </div>
</div>
<p className="text-xs text-muted-foreground">{t('satset.gridHint')}</p>
<div className="grid grid-cols-3 gap-3">
<div className="space-y-1"> <div className="space-y-1">
<Label>{t('satset.windowH')}</Label> <Label>{t('satset.windowH')}</Label>
<Input className="font-mono" value={String(satCfg.window_h ?? 24)} <Input className="font-mono" value={String(satCfg.window_h ?? 24)}
onChange={(e) => set('window_h', num(e.target.value))} /> onChange={(e) => set('window_h', num(e.target.value))} />
</div> </div>
</div> </div>
<p className="text-xs text-muted-foreground">{t('satset.altHint')}</p>
{/* The locator is NOT repeated here: it is the station's, set once in
Station information, and the passes are predicted from it. This is
the exception an antenna at another site and it says so, so
nobody has to wonder which of two locators is in use. */}
<details className="text-sm">
<summary className="cursor-pointer text-muted-foreground hover:text-foreground">
{t('satset.otherSite')}
</summary>
<div className="mt-2 flex items-center gap-3">
<Input className="font-mono w-40" placeholder={t('satset.gridPlaceholder')}
value={satCfg.grid ?? ''} onChange={(e) => set('grid', e.target.value.toUpperCase())} />
<span className="text-xs text-muted-foreground">{t('satset.otherSiteHint')}</span>
</div>
</details>
<div className="border-t border-border/60 pt-4 space-y-3"> <div className="border-t border-border/60 pt-4 space-y-3">
<h4 className="text-sm font-semibold text-foreground">{t('satset.rotor')}</h4> <h4 className="text-sm font-semibold text-foreground">{t('satset.rotor')}</h4>
@@ -4569,8 +4576,11 @@ function SettingsModalImpl({ onClose, onSaved, initialSection, onMainPaneChanged
<> <>
{/* Who drives the mast. Not a detail: a station already running {/* Who drives the mast. Not a detail: a station already running
PstRotator must NOT have OpsLog on the same cable as well. */} PstRotator must NOT have OpsLog on the same cable as well. */}
<div className="grid grid-cols-3 gap-3"> <div className="grid grid-cols-4 gap-3">
<div className="space-y-1"> {/* Two columns wide: "OpsLog (EasyComm II)" does not fit in a
third of the row, and a truncated choice is a choice an
operator cannot read. */}
<div className="space-y-1 col-span-2">
<Label>{t('satset.rotType')}</Label> <Label>{t('satset.rotType')}</Label>
<Select value={satCfg.rot_type || 'easycomm'} onValueChange={(v) => set('rot_type', v)}> <Select value={satCfg.rot_type || 'easycomm'} onValueChange={(v) => set('rot_type', v)}>
<SelectTrigger className="h-9"><SelectValue /></SelectTrigger> <SelectTrigger className="h-9"><SelectValue /></SelectTrigger>
+12 -4
View File
@@ -595,10 +595,14 @@ const en: Dict = {
'sat.geoHint': 'Geostationary: always there, no Doppler to correct. Point once and leave it.', 'sat.geoHint': 'Geostationary: always there, no Doppler to correct. Point once and leave it.',
'sat.noneFollowed': 'no satellite followed — choose some in Settings', 'sat.noneFollowed': 'no satellite followed — choose some in Settings',
'sat.tleStale': 'elements are old — refresh them in Settings', 'sat.tleStale': 'elements are old — refresh them in Settings',
'sat.hideSide': 'Hide the readout — all map', 'sat.showSide': 'Show the readout',
'sat.sideWidthTip': 'Drag to resize the readout. Double-click to reset it.',
'sec.satellite': 'Satellites', 'sec.satellite': 'Satellites',
'satset.hint': 'Where the antenna is, and the machine that points it. The satellites you follow and the frequency plan are in the Satellites tab.', 'satset.hint': 'Where the antenna is, and the machine that points it. The satellites you follow and the frequency plan are in the Satellites tab.',
'satset.grid': 'Locator', 'satset.gridPlaceholder': 'your stations', 'satset.gridPlaceholder': 'e.g. JN18cx',
'satset.gridHint': 'Leave the locator empty to use your stations own. Altitude is the antenna above sea level — it changes the horizon, and so the start and end of a low pass.', 'satset.altHint': 'Passes are predicted from your station locator (Station information). Altitude is the antenna above sea level — it changes the horizon, and so the start and end of a low pass. “Lowest pass” hides the ones that scrape the horizon and will never be a QSO.',
'satset.otherSite': 'The satellite antenna is at another site…',
'satset.otherSiteHint': 'Only fill this in if your satellite station is somewhere other than your logged locator. Empty means your stations own.',
'satset.altM': 'Altitude (m)', 'satset.minEl': 'Lowest pass (°)', 'satset.windowH': 'Predict ahead (hours)', 'satset.altM': 'Altitude (m)', 'satset.minEl': 'Lowest pass (°)', 'satset.windowH': 'Predict ahead (hours)',
'satset.autoTle': 'Fetch fresh elements at startup when they are more than three days old', 'satset.autoTle': 'Fetch fresh elements at startup when they are more than three days old',
'satset.rotor': 'Azimuth / elevation rotator', 'satset.rotor': 'Azimuth / elevation rotator',
@@ -1182,10 +1186,14 @@ const fr: Dict = {
'sat.geoHint': 'Géostationnaire : toujours là, aucun Doppler à corriger. On pointe une fois et on ny touche plus.', 'sat.geoHint': 'Géostationnaire : toujours là, aucun Doppler à corriger. On pointe une fois et on ny touche plus.',
'sat.noneFollowed': 'aucun satellite suivi — choisissez-en dans les Réglages', 'sat.noneFollowed': 'aucun satellite suivi — choisissez-en dans les Réglages',
'sat.tleStale': 'éléments anciens — actualisez-les dans les Réglages', 'sat.tleStale': 'éléments anciens — actualisez-les dans les Réglages',
'sat.hideSide': 'Masquer le panneau — carte plein écran', 'sat.showSide': 'Afficher le panneau',
'sat.sideWidthTip': 'Glisser pour redimensionner le panneau. Double-clic pour le remettre par défaut.',
'sec.satellite': 'Satellites', 'sec.satellite': 'Satellites',
'satset.hint': 'Où se trouve lantenne, et la machine qui la pointe. Les satellites suivis et le plan de fréquences sont dans longlet Satellites.', 'satset.hint': 'Où se trouve lantenne, et la machine qui la pointe. Les satellites suivis et le plan de fréquences sont dans longlet Satellites.',
'satset.grid': 'Locator', 'satset.gridPlaceholder': 'celui de la station', 'satset.gridPlaceholder': 'ex. JN18cx',
'satset.gridHint': 'Laissez le locator vide pour utiliser celui de votre station. Laltitude est celle de lantenne au-dessus du niveau de la mer — elle change lhorizon, donc le début et la fin dun passage rasant.', 'satset.altHint': 'Les passages sont calculés depuis le locator de votre station (Informations station). Laltitude est celle de lantenne au-dessus du niveau de la mer — elle change lhorizon, donc le début et la fin dun passage rasant. « Passage minimal » masque ceux qui rasent lhorizon et ne feront jamais un QSO.',
'satset.otherSite': 'Lantenne satellite est sur un autre site…',
'satset.otherSiteHint': 'À remplir seulement si votre station satellite est ailleurs que le locator de votre log. Vide = celui de votre station.',
'satset.altM': 'Altitude (m)', 'satset.minEl': 'Passage minimal (°)', 'satset.windowH': 'Prévoir sur (heures)', 'satset.altM': 'Altitude (m)', 'satset.minEl': 'Passage minimal (°)', 'satset.windowH': 'Prévoir sur (heures)',
'satset.autoTle': 'Récupérer des éléments frais au démarrage quand ils ont plus de trois jours', 'satset.autoTle': 'Récupérer des éléments frais au démarrage quand ils ont plus de trois jours',
'satset.rotor': 'Rotor azimut / élévation', 'satset.rotor': 'Rotor azimut / élévation',
+1
View File
@@ -59,6 +59,7 @@ const PORTABLE_KEYS = [
'opslog.clusterMuteWorked', // cluster/band map: no colour or badge on worked spots 'opslog.clusterMuteWorked', // cluster/band map: no colour or badge on worked spots
'opslog.clusterSlotHighlight', // cluster/band map: colour calls not worked on this band+mode 'opslog.clusterSlotHighlight', // cluster/band map: colour calls not worked on this band+mode
'opslog.bandMapWidth', // docked band map: column width (px) 'opslog.bandMapWidth', // docked band map: column width (px)
'opslog.satSideWidth', 'opslog.satSideShown', // Satellites tab: readout column width, and whether it is shown
'opslog.bandMapTabWidth', // Band map tab: shared card width (px) 'opslog.bandMapTabWidth', // Band map tab: shared card width (px)
'opslog.bandMapZoom', // band map zoom (px/kHz step) remembered per band, as one {band: index} map 'opslog.bandMapZoom', // band map zoom (px/kHz step) remembered per band, as one {band: index} map
'opslog.decodeColWidths', // FT decodes table: per-column widths (px), as one {col: px} map 'opslog.decodeColWidths', // FT decodes table: per-column widths (px), as one {col: px} map
+282 -14
View File
@@ -1,14 +1,18 @@
[ [
{ {
"name": "ISS (ZARYA)", "name": "ISS (ZARYA)",
"aliases": ["ISS", "ZARYA", "ARISS"], "aliases": [
"ISS",
"ZARYA",
"ARISS"
],
"transponders": [ "transponders": [
{ {
"label": "FM voice repeater", "label": "FM voice repeater",
"mode": "FM", "mode": "FM",
"down_lo": 437800000, "down_lo": 437800000,
"up_lo": 145990000, "up_lo": 145990000,
"ctcss": 67.0 "ctcss": 67
}, },
{ {
"label": "APRS digipeater", "label": "APRS digipeater",
@@ -25,33 +29,43 @@
}, },
{ {
"name": "SO-50", "name": "SO-50",
"aliases": ["SAUDISAT 1C", "SAUDISAT 1C (SO-50)"], "aliases": [
"SAUDISAT 1C",
"SAUDISAT 1C (SO-50)"
],
"transponders": [ "transponders": [
{ {
"label": "FM voice repeater", "label": "FM voice repeater",
"mode": "FM", "mode": "FM",
"down_lo": 436795000, "down_lo": 436795000,
"up_lo": 145850000, "up_lo": 145850000,
"ctcss": 67.0 "ctcss": 67
} }
] ]
}, },
{ {
"name": "AO-91", "name": "AO-91",
"aliases": ["RADFXSAT", "FOX-1B", "RADFXSAT (FOX-1B)"], "aliases": [
"RADFXSAT",
"FOX-1B",
"RADFXSAT (FOX-1B)"
],
"transponders": [ "transponders": [
{ {
"label": "FM voice repeater", "label": "FM voice repeater",
"mode": "FM", "mode": "FM",
"down_lo": 145960000, "down_lo": 145960000,
"up_lo": 435250000, "up_lo": 435250000,
"ctcss": 67.0 "ctcss": 67
} }
] ]
}, },
{ {
"name": "IO-86", "name": "IO-86",
"aliases": ["LAPAN-A2", "LAPAN-ORARI"], "aliases": [
"LAPAN-A2",
"LAPAN-ORARI"
],
"transponders": [ "transponders": [
{ {
"label": "FM voice repeater", "label": "FM voice repeater",
@@ -64,7 +78,10 @@
}, },
{ {
"name": "PO-101", "name": "PO-101",
"aliases": ["DIWATA-2", "DIWATA-2B"], "aliases": [
"DIWATA-2",
"DIWATA-2B"
],
"transponders": [ "transponders": [
{ {
"label": "FM voice repeater (scheduled)", "label": "FM voice repeater (scheduled)",
@@ -77,7 +94,10 @@
}, },
{ {
"name": "AO-7", "name": "AO-7",
"aliases": ["AMSAT-OSCAR 7", "OSCAR 7"], "aliases": [
"AMSAT-OSCAR 7",
"OSCAR 7"
],
"transponders": [ "transponders": [
{ {
"label": "Mode B linear (inverting)", "label": "Mode B linear (inverting)",
@@ -100,7 +120,10 @@
}, },
{ {
"name": "FO-29", "name": "FO-29",
"aliases": ["JAS-2", "FUJI-OSCAR 29"], "aliases": [
"JAS-2",
"FUJI-OSCAR 29"
],
"transponders": [ "transponders": [
{ {
"label": "Linear (inverting)", "label": "Linear (inverting)",
@@ -115,7 +138,10 @@
}, },
{ {
"name": "AO-73", "name": "AO-73",
"aliases": ["FUNCUBE-1", "FUNCUBE 1"], "aliases": [
"FUNCUBE-1",
"FUNCUBE 1"
],
"transponders": [ "transponders": [
{ {
"label": "Linear (inverting)", "label": "Linear (inverting)",
@@ -130,7 +156,10 @@
}, },
{ {
"name": "JO-97", "name": "JO-97",
"aliases": ["JY1SAT", "JY1-SAT"], "aliases": [
"JY1SAT",
"JY1-SAT"
],
"transponders": [ "transponders": [
{ {
"label": "Linear (inverting)", "label": "Linear (inverting)",
@@ -145,7 +174,9 @@
}, },
{ {
"name": "RS-44", "name": "RS-44",
"aliases": ["DOSAAF-85"], "aliases": [
"DOSAAF-85"
],
"transponders": [ "transponders": [
{ {
"label": "Linear (inverting)", "label": "Linear (inverting)",
@@ -160,7 +191,11 @@
}, },
{ {
"name": "QO-100", "name": "QO-100",
"aliases": ["ES'HAIL 2", "ESHAIL 2", "ES'HAIL-2"], "aliases": [
"ES'HAIL 2",
"ESHAIL 2",
"ES'HAIL-2"
],
"geostationary": true, "geostationary": true,
"transponders": [ "transponders": [
{ {
@@ -170,6 +205,239 @@
"down_hi": 10489800000, "down_hi": 10489800000,
"up_lo": 2400050000, "up_lo": 2400050000,
"up_hi": 2400300000 "up_hi": 2400300000
},
{
"label": "Wideband (DATV)",
"mode": "DATA",
"down_lo": 10491000000,
"down_hi": 10499000000,
"up_lo": 2401500000,
"up_hi": 2409500000
}
]
},
{
"name": "TEVEL-1",
"aliases": [
"TEVEL 1"
],
"transponders": [
{
"label": "FM voice repeater",
"mode": "FM",
"down_lo": 436400000,
"up_lo": 145970000,
"ctcss": 67
}
]
},
{
"name": "TEVEL-2",
"aliases": [
"TEVEL 2"
],
"transponders": [
{
"label": "FM voice repeater",
"mode": "FM",
"down_lo": 436400000,
"up_lo": 145970000,
"ctcss": 67
}
]
},
{
"name": "TEVEL-3",
"aliases": [
"TEVEL 3"
],
"transponders": [
{
"label": "FM voice repeater",
"mode": "FM",
"down_lo": 436400000,
"up_lo": 145970000,
"ctcss": 67
}
]
},
{
"name": "TEVEL-4",
"aliases": [
"TEVEL 4"
],
"transponders": [
{
"label": "FM voice repeater",
"mode": "FM",
"down_lo": 436400000,
"up_lo": 145970000,
"ctcss": 67
}
]
},
{
"name": "TEVEL-5",
"aliases": [
"TEVEL 5"
],
"transponders": [
{
"label": "FM voice repeater",
"mode": "FM",
"down_lo": 436400000,
"up_lo": 145970000,
"ctcss": 67
}
]
},
{
"name": "TEVEL-6",
"aliases": [
"TEVEL 6"
],
"transponders": [
{
"label": "FM voice repeater",
"mode": "FM",
"down_lo": 436400000,
"up_lo": 145970000,
"ctcss": 67
}
]
},
{
"name": "TEVEL-7",
"aliases": [
"TEVEL 7"
],
"transponders": [
{
"label": "FM voice repeater",
"mode": "FM",
"down_lo": 436400000,
"up_lo": 145970000,
"ctcss": 67
}
]
},
{
"name": "TEVEL-8",
"aliases": [
"TEVEL 8"
],
"transponders": [
{
"label": "FM voice repeater",
"mode": "FM",
"down_lo": 436400000,
"up_lo": 145970000,
"ctcss": 67
}
]
},
{
"name": "EO-88",
"aliases": [
"NAYIF-1",
"FUNCUBE-5"
],
"transponders": [
{
"label": "Linear (inverting)",
"mode": "SSB",
"down_lo": 145960000,
"down_hi": 145990000,
"up_lo": 435015000,
"up_hi": 435045000,
"inverting": true
}
]
},
{
"name": "AO-109",
"aliases": [
"RADFXSAT-2",
"FOX-1E"
],
"transponders": [
{
"label": "Linear (inverting)",
"mode": "SSB",
"down_lo": 145860000,
"down_hi": 145880000,
"up_lo": 435750000,
"up_hi": 435770000,
"inverting": true
}
]
},
{
"name": "CAS-4A",
"aliases": [
"ZHUHAI-1 OVS-1A",
"OVS-1A"
],
"transponders": [
{
"label": "Linear (inverting)",
"mode": "SSB",
"down_lo": 145860000,
"down_hi": 145880000,
"up_lo": 435210000,
"up_hi": 435230000,
"inverting": true
}
]
},
{
"name": "CAS-4B",
"aliases": [
"ZHUHAI-1 OVS-1B",
"OVS-1B"
],
"transponders": [
{
"label": "Linear (inverting)",
"mode": "SSB",
"down_lo": 145905000,
"down_hi": 145925000,
"up_lo": 435270000,
"up_hi": 435290000,
"inverting": true
}
]
},
{
"name": "TO-108",
"aliases": [
"CAS-6",
"TIANQIN-1"
],
"transponders": [
{
"label": "Linear (inverting)",
"mode": "SSB",
"down_lo": 145915000,
"down_hi": 145935000,
"up_lo": 435270000,
"up_hi": 435290000,
"inverting": true
}
]
},
{
"name": "IO-117",
"aliases": [
"GREENCUBE",
"MEZTLI"
],
"transponders": [
{
"label": "Digipeater (1200 bd GMSK)",
"mode": "DATA",
"down_lo": 435310000,
"up_lo": 435310000
} }
] ]
} }