radio: fix quick log insert (timestamp param), 'ch 16' falls back to the marine channel, ISS list fits half-width cards
All checks were successful
Deploy production / deploy (push) Successful in 1m26s

This commit is contained in:
2026-10-26 17:15:29 +00:00
parent 03574a95a7
commit 95a8b76562
2 changed files with 57 additions and 35 deletions

View File

@@ -65,35 +65,37 @@
> >
</div> </div>
{/if} {/if}
{#if days.length} <div class="iss">
{#each days as d (d.key)} {#if days.length}
<h3 class="day">{d.label}</h3> {#each days as d (d.key)}
<ul class="passes"> <h3 class="day">{d.label}</h3>
{#each d.passes as p (p.startAt)} <ul class="passes">
{@const live = new Date(p.startAt).getTime() <= now} {#each d.passes as p (p.startAt)}
<li class={{ low: p.maxEl < ISS_MIN_EL, live }}> {@const live = new Date(p.startAt).getTime() <= now}
<span class="times"> <li class={{ low: p.maxEl < ISS_MIN_EL, live }}>
<b>{fmtTime(p.startAt)}</b><span class="arrow">→</span>{fmtTime(p.maxAt)}<span <span class="times">
class="arrow">→</span <b>{fmtTime(p.startAt)}</b><span class="arrow">→</span>{fmtTime(p.maxAt)}<span
>{fmtTime(p.endAt)} class="arrow">→</span
</span> >{fmtTime(p.endAt)}
<span class="el" title="max elevation"> </span>
<span class="elbar"><i style:width="{Math.min(100, (p.maxEl / 90) * 100)}%"></i></span <span class="el" title="max elevation">
>{Math.round(p.maxEl)}° <span class="elbar"><i style:width="{Math.min(100, (p.maxEl / 90) * 100)}%"></i></span
</span> >{Math.round(p.maxEl)}°
<span class="dir">{compass(p.startAz)} → {compass(p.maxAz)} → {compass(p.endAz)}</span> </span>
<span class="dur">{mins(p)} min</span> <span class="dir">{compass(p.startAz)} → {compass(p.maxAz)} → {compass(p.endAz)}</span>
<span class="vis" <span class="dur">{mins(p)} min</span>
>{#if p.sunlit}<Eye size={14} aria-label="visible to the eye" />{/if}</span <span class="vis"
> >{#if p.sunlit}<Eye size={14} aria-label="visible to the eye" />{/if}</span
<span class="rel">{live ? 'overhead now' : until(p.startAt, now)}</span> >
</li> <span class="rel">{live ? 'overhead now' : until(p.startAt, now)}</span>
{/each} </li>
</ul> {/each}
{/each} </ul>
{:else} {/each}
<p class="empty">No passes computed yet (the daily refresh fills this).</p> {:else}
{/if} <p class="empty">No passes computed yet (the daily refresh fills this).</p>
{/if}
</div>
{#if !compact && tle} {#if !compact && tle}
<p class="meta foot"> <p class="meta foot">
{tle.name} TLE from Celestrak, epoch {tle.epoch ? fmtAgo(tle.epoch) : '?'}, fetched {tle.fetchedAt {tle.name} TLE from Celestrak, epoch {tle.epoch ? fmtAgo(tle.epoch) : '?'}, fetched {tle.fetchedAt
@@ -177,16 +179,31 @@
.foot { .foot {
margin-top: 0.8rem; margin-top: 0.8rem;
} }
@media (max-width: 640px) { .iss {
container-type: inline-size;
}
@container (max-width: 40rem) {
li { li {
grid-template-columns: 1fr auto auto; grid-template-columns: minmax(0, 1fr) auto 1.2rem;
row-gap: 0.1rem; row-gap: 0.1rem;
} }
.times {
grid-area: 1 / 1;
}
.el {
grid-area: 1 / 2;
}
.vis {
grid-area: 1 / 3;
}
.dir { .dir {
grid-column: 1; grid-area: 2 / 1;
} }
.dur { .dur {
display: none; display: none;
} }
.rel {
grid-area: 2 / 2 / 3 / 4;
}
} }
</style> </style>

View File

@@ -320,10 +320,15 @@ export async function addLog(form: FormData): Promise<Result> {
if (typed && !frequencyId) { if (typed && !frequencyId) {
const ch = typed.match(/^ch\s*(\d{1,3})$/i); const ch = typed.match(/^ch\s*(\d{1,3})$/i);
if (ch) { if (ch) {
// A scanner memory first; banks 1-3 are empty, so "ch 16" there means marine channel 16.
const [r] = const [r] =
await client`SELECT frequency_id FROM radio.channels WHERE channel = ${Number(ch[1])}`; await client`SELECT frequency_id FROM radio.channels WHERE channel = ${Number(ch[1])}`;
if (!r) return { ok: false, message: `Channel ${ch[1]} is empty.` }; const [m] = r
frequencyId = r.frequency_id; ? [null]
: await client`SELECT id FROM radio.frequencies WHERE marine_ch = ${ch[1]}
ORDER BY (SELECT count(*) FROM radio.channels c WHERE c.frequency_id = id) DESC, id LIMIT 1`;
if (!r && !m) return { ok: false, message: `Channel ${ch[1]} is empty.` };
frequencyId = r ? r.frequency_id : m!.id;
} else { } else {
freqHz = parseFreq(typed); freqHz = parseFreq(typed);
if (!freqHz) return { ok: false, message: 'Frequency not understood.' }; if (!freqHz) return { ok: false, message: 'Frequency not understood.' };
@@ -349,7 +354,7 @@ export async function addLog(form: FormData): Promise<Result> {
heardAt = fromZoned(+m[1], +m[2], +m[3], +m[4], +m[5]); heardAt = fromZoned(+m[1], +m[2], +m[3], +m[4], +m[5]);
} }
await client`INSERT INTO radio.log ${client({ await client`INSERT INTO radio.log ${client({
heard_at: heardAt, heard_at: heardAt.toISOString(),
frequency_id: frequencyId, frequency_id: frequencyId,
freq_hz: freqHz, freq_hz: freqHz,
mode, mode,