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
All checks were successful
Deploy production / deploy (push) Successful in 1m26s
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user