radio: classic ham-site public view (Opa's Radiohoek) with link directory
Deploy production / deploy (push) Successful in 1m23s
Deploy production / deploy (push) Successful in 1m23s
- PublicRadio.svelte: websdr.org-style grey page, steel-blue bars, dense tables, NL default / EN toggle, radio facts, frequency list per band, banks, ISS, nets - links.ts: all 34 showcase links, status (online/warn/offline) + archive links - owner keeps the dashboard; ?view=public lets the owner preview the public page
This commit is contained in:
1 parent
3a2d3cc78c
commit
2c8d1bd881
4 files changed
+1684
-107
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,453 @@
|
||||
// Link directory for the public radio page (/trackers/radio#links), from the links Opa sent by
|
||||
// email and WhatsApp (checked 24 Oct 2026). Plain data: add or edit entries here. Every entry is
|
||||
// shown; offline ones get a label and, when there is one, a web.archive.org copy. Public sites only:
|
||||
// never add a phone number, an email address or a link into someone's own mailbox.
|
||||
export type Text = { nl: string; en: string };
|
||||
export type LinkStatus = 'online' | 'warn' | 'offline';
|
||||
export type RadioLink = {
|
||||
title: string;
|
||||
/** An http(s) URL, or "#anchor" for a section on this page. */
|
||||
url: string;
|
||||
about: Text;
|
||||
/** How it reached us: Opa by email or WhatsApp, or a supporting link we added. */
|
||||
via: 'email' | 'whatsapp' | 'added';
|
||||
/** Date Opa sent it (YYYY-MM-DD), when known. */
|
||||
sent?: string;
|
||||
status: LinkStatus;
|
||||
archive?: string;
|
||||
note?: Text;
|
||||
};
|
||||
export type LinkCategory = { id: string; title: Text; links: RadioLink[] };
|
||||
|
||||
export const LINKS_CHECKED = '2026-10-24';
|
||||
|
||||
export const LINK_CATEGORIES: LinkCategory[] = [
|
||||
{
|
||||
id: 'websdr',
|
||||
title: {
|
||||
nl: 'WebSDR — luisteren via de browser',
|
||||
en: 'WebSDR — listen in the browser'
|
||||
},
|
||||
links: [
|
||||
{
|
||||
title: 'websdr.org',
|
||||
url: 'http://websdr.org/',
|
||||
about: {
|
||||
nl: 'Overzicht en kaart van alle WebSDR-ontvangers ter wereld',
|
||||
en: 'Directory and map of every WebSDR receiver worldwide'
|
||||
},
|
||||
via: 'whatsapp',
|
||||
status: 'online'
|
||||
},
|
||||
{
|
||||
title: 'WebSDR Universiteit Twente',
|
||||
url: 'http://websdr.ewi.utwente.nl:8901/',
|
||||
about: {
|
||||
nl: '0–29 MHz, de allereerste WebSDR',
|
||||
en: '0–29 MHz, the original WebSDR'
|
||||
},
|
||||
via: 'whatsapp',
|
||||
status: 'online'
|
||||
},
|
||||
{
|
||||
title: 'WebSDR Maasbree (PH4RTM)',
|
||||
url: 'http://sdr.websdrmaasbree.nl:8901/',
|
||||
about: {
|
||||
nl: 'Kortegolf, o.a. de KLM-ronde op 3785 kHz LSB',
|
||||
en: 'Shortwave, e.g. the KLM net on 3785 kHz LSB'
|
||||
},
|
||||
via: 'whatsapp',
|
||||
status: 'online',
|
||||
sent: '2026-09-20'
|
||||
},
|
||||
{
|
||||
title: 'WebSDR PI1DFT (OpenWebRX+)',
|
||||
url: 'https://websdr.pi1dft.ampr.org/#freq=145450000,mod=nfm,sql=-66',
|
||||
about: {
|
||||
nl: 'Delft/Den Haag, al afgestemd op 145.450 NFM: de Haagse ronde',
|
||||
en: 'Delft/The Hague, pre-tuned to 145.450 NFM for the Hague net'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-07'
|
||||
},
|
||||
{
|
||||
title: 'WebSDR Utrecht (PI4UTR)',
|
||||
url: 'https://websdr.pi4utr.nl/',
|
||||
about: {
|
||||
nl: 'WebSDR Utrecht van PI4UTR',
|
||||
en: 'WebSDR Utrecht run by PI4UTR'
|
||||
},
|
||||
via: 'whatsapp',
|
||||
status: 'offline',
|
||||
note: {
|
||||
nl: 'adres niet bereikbaar; zie de site van PI4UTR hieronder',
|
||||
en: 'address unreachable; see the PI4UTR site below'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'PI4UTR',
|
||||
url: 'https://www.pi4utr.nl/',
|
||||
about: {
|
||||
nl: 'VERON-afdeling Utrecht, beheert de Utrechtse WebSDR',
|
||||
en: 'VERON Utrecht club, runs the Utrecht WebSDR'
|
||||
},
|
||||
via: 'added',
|
||||
status: 'online'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'air',
|
||||
title: {
|
||||
nl: 'Luchtvaart en ADS-B (1090 MHz)',
|
||||
en: 'Aviation and ADS-B (1090 MHz)'
|
||||
},
|
||||
links: [
|
||||
{
|
||||
title: 'RTL-SDR: ADS-B-radar',
|
||||
url: 'https://www.rtl-sdr.com/adsb-aircraft-radar-with-rtl-sdr/',
|
||||
about: {
|
||||
nl: 'Eigen vliegtuigradar met een RTL-SDR-stickje',
|
||||
en: 'Build your own aircraft radar with an RTL-SDR dongle'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-06'
|
||||
},
|
||||
{
|
||||
title: 'Flightradar24: ADS-B-antenne',
|
||||
url: 'https://www.flightradar24.com/blog/ads-b/ads-b-antenna-and-location-guide/',
|
||||
about: {
|
||||
nl: 'Waar en hoe je een ADS-B-antenne plaatst',
|
||||
en: 'Where and how to place an ADS-B antenna'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-06'
|
||||
},
|
||||
{
|
||||
title: 'SDRshop: ADS-B-antenne',
|
||||
url: 'https://sdrshop.nl/ads-b-antenne/',
|
||||
about: {
|
||||
nl: 'ADS-B-antenne (1090 MHz)',
|
||||
en: 'ADS-B antenna (1090 MHz)'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-06'
|
||||
},
|
||||
{
|
||||
title: 'Elektor: ADS-B buitenantenne',
|
||||
url: 'https://www.elektor.nl/products/ads-b-outdoor-antenna-1090-mhz',
|
||||
about: {
|
||||
nl: 'ADS-B buitenantenne 1090 MHz',
|
||||
en: 'Outdoor 1090 MHz ADS-B antenna'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-06'
|
||||
},
|
||||
{
|
||||
title: 'Van Dijken: De Flight-antenne',
|
||||
url: 'https://www.vandijkenelektronica.nl/product/de-flight-antenna-voor-ontvangst-van-ads-b-signalen-op-1090-mhz/',
|
||||
about: {
|
||||
nl: '“De Flight”-antenne voor ADS-B op 1090 MHz',
|
||||
en: '“De Flight” antenna for ADS-B on 1090 MHz'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-06'
|
||||
},
|
||||
{
|
||||
title: 'RTL-SDR: FlightAware-antenne',
|
||||
url: 'https://www.rtl-sdr.com/review-flightaware-ads-b-antenna-and-filter/',
|
||||
about: {
|
||||
nl: 'Review van de FlightAware ADS-B-antenne en filter',
|
||||
en: 'Review of the FlightAware ADS-B antenna and filter'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-06'
|
||||
},
|
||||
{
|
||||
title: 'Linux Magazine: Raspberry Pi',
|
||||
url: 'https://linuxmag.nl/vliegtuigen-spotten-met-je-raspberry-pi/',
|
||||
about: {
|
||||
nl: 'Vliegtuigen spotten met een Raspberry Pi',
|
||||
en: 'Plane spotting with a Raspberry Pi'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-11'
|
||||
},
|
||||
{
|
||||
title: 'PD0G: ADS-B decoderen',
|
||||
url: 'https://pd0g.wordpress.com/2018/04/02/ads-b-decoding-with-rtl-sdr-adsbsharp-and-virtual-radar-server/',
|
||||
about: {
|
||||
nl: 'ADS-B met RTL-SDR, ADSBSharp en Virtual Radar Server',
|
||||
en: 'ADS-B with RTL-SDR, ADSBSharp and Virtual Radar Server'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-11'
|
||||
},
|
||||
{
|
||||
title: 'PD2EW: ADS-B',
|
||||
url: 'https://www.wijkamp.com/pd2ew/ads-b.html',
|
||||
about: {
|
||||
nl: 'ADS-B-pagina van zendamateur PD2EW',
|
||||
en: "A ham's ADS-B page (PD2EW)"
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-11'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'iss',
|
||||
title: {
|
||||
nl: 'ISS en satellieten',
|
||||
en: 'ISS and satellites'
|
||||
},
|
||||
links: [
|
||||
{
|
||||
title: 'ARISS live',
|
||||
url: 'https://live.ariss.org/',
|
||||
about: {
|
||||
nl: 'Radiocontacten tussen scholen en de ISS (145.800 MHz)',
|
||||
en: 'Radio contacts between schools and the ISS (145.800 MHz)'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2022-12-08'
|
||||
},
|
||||
{
|
||||
title: 'Weerstation Grootegast',
|
||||
url: 'https://www.weerstation-grootegast.nl/pagina32.html',
|
||||
about: {
|
||||
nl: 'Ontvangst van NOAA-weersatellieten',
|
||||
en: 'Receiving NOAA weather satellites'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'warn',
|
||||
sent: '2025-03-06',
|
||||
archive:
|
||||
'https://web.archive.org/web/20250611043333/https://weerstation-grootegast.nl/pagina32.html',
|
||||
note: {
|
||||
nl: 'verouderde beveiliging, opent soms niet; gebruik dan het archief',
|
||||
en: 'outdated security, may not open; use the archive copy'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'marine',
|
||||
title: {
|
||||
nl: 'Marifoon',
|
||||
en: 'Marine VHF'
|
||||
},
|
||||
links: [
|
||||
{
|
||||
title: "Opa's marifoonlijst (banken 7–10)",
|
||||
url: '#band-marine',
|
||||
about: {
|
||||
nl: 'Kanaal 301–495, staat in de frequentielijst op deze pagina',
|
||||
en: 'Channels 301–495, included in the frequency list on this page'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-05-21'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'sdr',
|
||||
title: {
|
||||
nl: 'Scanner en SDR: apparatuur en software',
|
||||
en: 'Scanner and SDR: hardware and software'
|
||||
},
|
||||
links: [
|
||||
{
|
||||
title: 'SDRshop: SDRplay RSP',
|
||||
url: 'https://sdrshop.nl/sdrplayrsp/',
|
||||
about: {
|
||||
nl: 'SDRplay RSP-ontvangers (Opa heeft de RSP1B)',
|
||||
en: 'SDRplay RSP receivers (Opa has the RSP1B)'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-06'
|
||||
},
|
||||
{
|
||||
title: 'SDRshop: SDRplay-overzicht',
|
||||
url: 'https://sdrshop.nl/sdrplay-overzicht/',
|
||||
about: {
|
||||
nl: 'Vergelijking van alle SDRplay-modellen',
|
||||
en: 'Comparison of all SDRplay models'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-06'
|
||||
},
|
||||
{
|
||||
title: 'SDRshop: SDRuno-boek',
|
||||
url: 'https://sdrshop.nl/sdrplay-en-sdruno-boek/',
|
||||
about: {
|
||||
nl: 'Nederlandstalig SDRplay/SDRuno-boek (ADS-B op blz. 140)',
|
||||
en: 'Dutch SDRplay/SDRuno handbook (ADS-B on p. 140)'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-06'
|
||||
},
|
||||
{
|
||||
title: 'SDRuno-boek: inhoud (pdf)',
|
||||
url: 'https://sdrshop.nl/wp-content/uploads/SDRuno-handleiding-inhoud-1.pdf',
|
||||
about: {
|
||||
nl: 'Inhoudsopgave van dat boek',
|
||||
en: 'Table of contents of that book'
|
||||
},
|
||||
via: 'added',
|
||||
status: 'online'
|
||||
},
|
||||
{
|
||||
title: 'SDRplay RSP1B',
|
||||
url: 'https://www.sdrplay.com/rsp1b/',
|
||||
about: {
|
||||
nl: 'Officiële pagina van de RSP1B',
|
||||
en: 'Official RSP1B page'
|
||||
},
|
||||
via: 'added',
|
||||
status: 'online'
|
||||
},
|
||||
{
|
||||
title: 'RTL-SDR.com',
|
||||
url: 'https://www.rtl-sdr.com/',
|
||||
about: {
|
||||
nl: "Nieuws en projecten met goedkope SDR's",
|
||||
en: 'News and projects with cheap SDRs'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-06'
|
||||
},
|
||||
{
|
||||
title: 'RTL-SDR: wat is het?',
|
||||
url: 'https://www.rtl-sdr.com/about-rtl-sdr/',
|
||||
about: {
|
||||
nl: 'Wat is een RTL-SDR?',
|
||||
en: 'What is an RTL-SDR?'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-06'
|
||||
},
|
||||
{
|
||||
title: 'PC5E: frequentielijst Nederland (pdf)',
|
||||
url: 'https://www.pc5e.nl/downloads/scanner/20240102%20Frequenties%20Nederland.pdf',
|
||||
about: {
|
||||
nl: 'Lijst van PC5E, 2 jan 2024, 364 blz., op pc5e.nl',
|
||||
en: "PC5E's list, 2 Jan 2024, 364 pages, on pc5e.nl"
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-06'
|
||||
},
|
||||
{
|
||||
title: 'PC5E',
|
||||
url: 'https://www.pc5e.nl/',
|
||||
about: {
|
||||
nl: 'Homepage van zendamateur PC5E (Heerenveen), met scannerfrequenties',
|
||||
en: 'Homepage of ham PC5E (Heerenveen), with scanner frequencies'
|
||||
},
|
||||
via: 'whatsapp',
|
||||
status: 'online'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'forums',
|
||||
title: {
|
||||
nl: 'Forums en clubs',
|
||||
en: 'Forums and clubs'
|
||||
},
|
||||
links: [
|
||||
{
|
||||
title: 'Het Scannerforum',
|
||||
url: 'https://www.scannerforum.nl/',
|
||||
about: {
|
||||
nl: 'Alles over scanners, frequenties en P2000',
|
||||
en: 'Dutch scanner, frequency and P2000 forum'
|
||||
},
|
||||
via: 'whatsapp',
|
||||
status: 'online'
|
||||
},
|
||||
{
|
||||
title: 'Scannerforum: zoeken',
|
||||
url: 'https://www.scannerforum.nl/index.php?action=search2',
|
||||
about: {
|
||||
nl: 'Zoekpagina (zoek op “ads-b”)',
|
||||
en: 'Search page (search for “ads-b”)'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-06'
|
||||
},
|
||||
{
|
||||
title: 'Zendamateur.com',
|
||||
url: 'https://www.zendamateur.com/',
|
||||
about: {
|
||||
nl: '“24 uur per dag QRV”, het NL/BE-radioamateurforum (inloggen aanbevolen)',
|
||||
en: '“On the air 24/7”, the Dutch/Belgian ham forum (logging in recommended)'
|
||||
},
|
||||
via: 'whatsapp',
|
||||
status: 'online'
|
||||
},
|
||||
{
|
||||
title: 'Zendamateur.com: ADS-B-topic',
|
||||
url: 'https://www.zendamateur.com/viewtopic.php?t=26620',
|
||||
about: {
|
||||
nl: 'Forumtopic over ADS-B',
|
||||
en: 'Forum topic about ADS-B'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-06'
|
||||
},
|
||||
{
|
||||
title: 'QRZ.com: PA4VB',
|
||||
url: 'https://www.qrz.com/db/PA4VB',
|
||||
about: {
|
||||
nl: 'QRZ-pagina van roepnaam PA4VB (details na inloggen)',
|
||||
en: 'QRZ page for callsign PA4VB (details need a login)'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2026-10-01'
|
||||
},
|
||||
{
|
||||
title: 'VRZA Zuid-West (PI4ZWN)',
|
||||
url: 'https://www.pi4zwn.nl/',
|
||||
about: {
|
||||
nl: 'Afdelingsnieuws en agenda',
|
||||
en: 'Club news and calendar'
|
||||
},
|
||||
via: 'added',
|
||||
status: 'online'
|
||||
},
|
||||
{
|
||||
title: 'PI4ZWN: SDRplay populair',
|
||||
url: 'https://www.pi4zwn.nl/sdrplay-blijkt-populaire-ontvanger/',
|
||||
about: {
|
||||
nl: 'Artikel: “SDRplay blijkt populaire ontvanger”',
|
||||
en: 'Article: “SDRplay turns out to be a popular receiver”'
|
||||
},
|
||||
via: 'email',
|
||||
status: 'online',
|
||||
sent: '2025-03-07'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
@@ -20,7 +20,9 @@ import type { Actions, PageServerLoad } from './$types';
|
||||
// below check the owner, and hooks.server.ts refuses non-GET requests here (ownerWritePrefixes).
|
||||
// Language: ?lang=nl|en (remembered in a cookie), else the cookie, else Accept-Language, else NL.
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
const owner = isOwner(event);
|
||||
const isOwnerReq = isOwner(event);
|
||||
// ?view=public lets the owner preview exactly what visitors get.
|
||||
const owner = isOwnerReq && event.url.searchParams.get('view') !== 'public';
|
||||
// Varies by login, cookie and Accept-Language, so never cache it in between.
|
||||
event.setHeaders({ 'cache-control': 'private, no-store', vary: 'cookie, accept-language' });
|
||||
const asked = event.url.searchParams.get('lang');
|
||||
@@ -41,6 +43,7 @@ export const load: PageServerLoad = async (event) => {
|
||||
return {
|
||||
...(owner ? radio : publicRadio(radio)),
|
||||
owner,
|
||||
ownerPreview: isOwnerReq && !owner,
|
||||
lang,
|
||||
now: Date.now(),
|
||||
seo: {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
import Nets from '#lib/radio/Nets.svelte';
|
||||
import IssPasses from '#lib/radio/IssPasses.svelte';
|
||||
import LogList from '#lib/radio/LogList.svelte';
|
||||
import PublicRadio from '#lib/radio/PublicRadio.svelte';
|
||||
import { BANDS } from '#lib/radio/index.js';
|
||||
import { DICTS, LANGS, setRadio } from '#lib/radio/i18n.js';
|
||||
import LayoutDashboard from 'lucide-svelte/icons/layout-dashboard';
|
||||
@@ -91,125 +92,142 @@
|
||||
resolve(`/trackers/radio?tab=frequencies&band=${band}` as '/');
|
||||
</script>
|
||||
|
||||
<div class="radio" lang={data.lang}>
|
||||
<header class="head">
|
||||
<a href={resolve('/trackers/radio')} class="title-link" aria-label={t.title}
|
||||
><TrackerIcon name="radio" class="size-12" /></a
|
||||
>
|
||||
<div class="title">
|
||||
<h1>{t.title}</h1>
|
||||
<p>{data.owner ? t.intro : t.introPublic}</p>
|
||||
</div>
|
||||
<nav class="lang" aria-label={t.language}>
|
||||
<span class="lang-icon" aria-hidden="true"><Languages size={18} /></span>
|
||||
{#each LANGS as l (l)}
|
||||
<!-- Visitors (and the owner with ?view=public) get the classic ham-site page; the owner gets
|
||||
the dashboard with edit controls. -->
|
||||
{#if !data.owner}
|
||||
<PublicRadio
|
||||
frequencies={data.frequencies}
|
||||
channels={data.channels}
|
||||
nets={data.nets}
|
||||
passes={data.passes}
|
||||
log={data.log}
|
||||
logTotal={data.logTotal}
|
||||
lang={data.lang}
|
||||
{now}
|
||||
{langHref}
|
||||
ownerPreview={data.ownerPreview}
|
||||
/>
|
||||
{:else}
|
||||
<div class="radio" lang={data.lang}>
|
||||
<header class="head">
|
||||
<a href={resolve('/trackers/radio')} class="title-link" aria-label={t.title}
|
||||
><TrackerIcon name="radio" class="size-12" /></a
|
||||
>
|
||||
<div class="title">
|
||||
<h1>{t.title}</h1>
|
||||
<p>{data.owner ? t.intro : t.introPublic}</p>
|
||||
</div>
|
||||
<nav class="lang" aria-label={t.language}>
|
||||
<span class="lang-icon" aria-hidden="true"><Languages size={18} /></span>
|
||||
{#each LANGS as l (l)}
|
||||
<a
|
||||
href={langHref(l)}
|
||||
hreflang={l}
|
||||
class={{ active: data.lang === l }}
|
||||
aria-current={data.lang === l ? 'true' : undefined}
|
||||
data-sveltekit-noscroll
|
||||
data-sveltekit-replacestate>{l === 'nl' ? 'NL' : 'EN'}</a
|
||||
>
|
||||
{/each}
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<nav class="tabs" aria-label={t.tabsLabel}>
|
||||
{#each TABS as x (x.id)}
|
||||
{@const n = count(x.id)}
|
||||
<a
|
||||
href={langHref(l)}
|
||||
hreflang={l}
|
||||
class={{ active: data.lang === l }}
|
||||
aria-current={data.lang === l ? 'true' : undefined}
|
||||
data-sveltekit-noscroll
|
||||
data-sveltekit-replacestate>{l === 'nl' ? 'NL' : 'EN'}</a
|
||||
href={tabHref(x.id)}
|
||||
class={{ active: tab === x.id }}
|
||||
aria-current={tab === x.id ? 'page' : undefined}
|
||||
><Tile icon={x.icon} from={x.c[0]} to={x.c[1]} size={28} /><span class="lbl"
|
||||
>{t.tabs[x.id]}</span
|
||||
>{#if n !== null}<span class="n">{n}</span>{/if}</a
|
||||
>
|
||||
{/each}
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<nav class="tabs" aria-label={t.tabsLabel}>
|
||||
{#each TABS as x (x.id)}
|
||||
{@const n = count(x.id)}
|
||||
<a
|
||||
href={tabHref(x.id)}
|
||||
class={{ active: tab === x.id }}
|
||||
aria-current={tab === x.id ? 'page' : undefined}
|
||||
><Tile icon={x.icon} from={x.c[0]} to={x.c[1]} size={28} /><span class="lbl"
|
||||
>{t.tabs[x.id]}</span
|
||||
>{#if n !== null}<span class="n">{n}</span>{/if}</a
|
||||
>
|
||||
{/each}
|
||||
</nav>
|
||||
|
||||
{#if tab === 'overview'}
|
||||
<div class="overview">
|
||||
<section class="card">
|
||||
<h2 class="card-title">
|
||||
<Tile icon={TABS[3].icon} from="#fbbf24" to="#b45309" size={24} />{t.upNext}
|
||||
</h2>
|
||||
<UpNext nets={data.nets} passes={data.passes} frequencies={data.frequencies} {now} />
|
||||
</section>
|
||||
{#if tab === 'overview'}
|
||||
<div class="overview">
|
||||
<section class="card">
|
||||
<h2 class="card-title">
|
||||
<Tile icon={TABS[3].icon} from="#fbbf24" to="#b45309" size={24} />{t.upNext}
|
||||
</h2>
|
||||
<UpNext nets={data.nets} passes={data.passes} frequencies={data.frequencies} {now} />
|
||||
</section>
|
||||
{#if data.owner}
|
||||
<section class="card">
|
||||
<h2 class="card-title">
|
||||
<Tile icon={TABS[5].icon} from="#34d399" to="#047857" size={24} />{t.quickLog}
|
||||
</h2>
|
||||
<QuickLog frequencies={data.frequencies} message={logMessage} error={logError} />
|
||||
<div class="recent">
|
||||
<LogList log={data.log} frequencies={data.frequencies} {now} limit={5} />
|
||||
</div>
|
||||
</section>
|
||||
{:else}
|
||||
<section class="card">
|
||||
<h2 class="card-title">
|
||||
<Tile icon={TABS[1].icon} from="#a78bfa" to="#5b21b6" size={24} />{t.byBand}
|
||||
</h2>
|
||||
<ul class="bands">
|
||||
{#each bandCounts as b (b.band)}
|
||||
<li>
|
||||
<a href={freqsHref(b.band)}
|
||||
><BandIcon band={b.band} size={32} /><span class="bn">{t.bands[b.band]}</span
|
||||
><span class="bc">{b.n}</span></a
|
||||
>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</section>
|
||||
{/if}
|
||||
<section class="card">
|
||||
<h2 class="card-title">
|
||||
<Tile icon={TABS[4].icon} from="#2dd4bf" to="#0f766e" size={24} />{t.nextIss}
|
||||
<a class="more" href={tabHref('iss')}>{t.all}</a>
|
||||
</h2>
|
||||
<IssPasses passes={data.passes} {now} limit={4} compact />
|
||||
</section>
|
||||
<section class="card stats">
|
||||
<h2 class="card-title">
|
||||
<Tile icon={TABS[2].icon} from="#38bdf8" to="#0369a1" size={24} />{t.scanner}
|
||||
</h2>
|
||||
<p>{t.channelsProgrammed(data.channels.length, data.frequencies.length)}</p>
|
||||
<p class="meta">{t.scanHelp}</p>
|
||||
<a class="ghost" href={tabHref('banks')}>{t.openBanks}</a>
|
||||
</section>
|
||||
{#if !data.owner && data.log.length}
|
||||
<section class="card">
|
||||
<h2 class="card-title">
|
||||
<Tile icon={TABS[5].icon} from="#34d399" to="#047857" size={24} />{t.recentLog}
|
||||
</h2>
|
||||
<LogList log={data.log} frequencies={data.frequencies} {now} limit={5} />
|
||||
</section>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if tab === 'frequencies'}
|
||||
<FreqList frequencies={data.frequencies} />
|
||||
{:else if tab === 'banks'}
|
||||
<Banks channels={data.channels} frequencies={data.frequencies} />
|
||||
{:else if tab === 'nets'}
|
||||
<Nets nets={data.nets} frequencies={data.frequencies} {now} />
|
||||
{:else if tab === 'iss'}
|
||||
<section class="card"><IssPasses passes={data.passes} tle={data.tle} {now} /></section>
|
||||
{:else}
|
||||
{#if data.owner}
|
||||
<section class="card">
|
||||
<h2 class="card-title">
|
||||
<Tile icon={TABS[5].icon} from="#34d399" to="#047857" size={24} />{t.quickLog}
|
||||
</h2>
|
||||
<QuickLog frequencies={data.frequencies} message={logMessage} error={logError} />
|
||||
<div class="recent">
|
||||
<LogList log={data.log} frequencies={data.frequencies} {now} limit={5} />
|
||||
</div>
|
||||
</section>
|
||||
{:else}
|
||||
<section class="card">
|
||||
<h2 class="card-title">
|
||||
<Tile icon={TABS[1].icon} from="#a78bfa" to="#5b21b6" size={24} />{t.byBand}
|
||||
</h2>
|
||||
<ul class="bands">
|
||||
{#each bandCounts as b (b.band)}
|
||||
<li>
|
||||
<a href={freqsHref(b.band)}
|
||||
><BandIcon band={b.band} size={32} /><span class="bn">{t.bands[b.band]}</span
|
||||
><span class="bc">{b.n}</span></a
|
||||
>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</section>
|
||||
{/if}
|
||||
<section class="card">
|
||||
<h2 class="card-title">
|
||||
<Tile icon={TABS[4].icon} from="#2dd4bf" to="#0f766e" size={24} />{t.nextIss}
|
||||
<a class="more" href={tabHref('iss')}>{t.all}</a>
|
||||
</h2>
|
||||
<IssPasses passes={data.passes} {now} limit={4} compact />
|
||||
</section>
|
||||
<section class="card stats">
|
||||
<h2 class="card-title">
|
||||
<Tile icon={TABS[2].icon} from="#38bdf8" to="#0369a1" size={24} />{t.scanner}
|
||||
</h2>
|
||||
<p>{t.channelsProgrammed(data.channels.length, data.frequencies.length)}</p>
|
||||
<p class="meta">{t.scanHelp}</p>
|
||||
<a class="ghost" href={tabHref('banks')}>{t.openBanks}</a>
|
||||
</section>
|
||||
{#if !data.owner && data.log.length}
|
||||
<section class="card">
|
||||
<h2 class="card-title">
|
||||
<Tile icon={TABS[5].icon} from="#34d399" to="#047857" size={24} />{t.recentLog}
|
||||
</h2>
|
||||
<LogList log={data.log} frequencies={data.frequencies} {now} limit={5} />
|
||||
</section>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if tab === 'frequencies'}
|
||||
<FreqList frequencies={data.frequencies} />
|
||||
{:else if tab === 'banks'}
|
||||
<Banks channels={data.channels} frequencies={data.frequencies} />
|
||||
{:else if tab === 'nets'}
|
||||
<Nets nets={data.nets} frequencies={data.frequencies} {now} />
|
||||
{:else if tab === 'iss'}
|
||||
<section class="card"><IssPasses passes={data.passes} tle={data.tle} {now} /></section>
|
||||
{:else}
|
||||
{#if data.owner}
|
||||
<section class="card">
|
||||
<QuickLog frequencies={data.frequencies} message={logMessage} error={logError} />
|
||||
{#if logFreq}<p class="meta">
|
||||
{t.oneFreq} <a href={tabHref('log')} class="u">{t.showAllLog}</a>
|
||||
</p>{/if}
|
||||
<LogList log={data.log} frequencies={data.frequencies} {now} frequencyId={logFreq} />
|
||||
</section>
|
||||
{/if}
|
||||
<section class="card">
|
||||
{#if logFreq}<p class="meta">
|
||||
{t.oneFreq} <a href={tabHref('log')} class="u">{t.showAllLog}</a>
|
||||
</p>{/if}
|
||||
<LogList log={data.log} frequencies={data.frequencies} {now} frequencyId={logFreq} />
|
||||
</section>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
/* Built to be read by an older visitor on a phone or tablet: big type, strong contrast, large
|
||||
|
||||
Reference in new issue
Block a user