[feat](trx-frontend-http): add Live/History views to Weather Satellites panel
Replace flat image list with two switchable views: - Live: decoder state cards (Idle/Listening), descriptions, latest image - History: filterable table with columns for time, type, satellite, channels, lines, and download link. Supports text filter, type filter (All/APT/LRPT), and sort order (newest/oldest). https://claude.ai/code/session_01JA13DHuzuHUL4nSBBRU83f Signed-off-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -3247,6 +3247,7 @@ function render(update) {
|
|||||||
lrptToggleBtn.style.borderColor = lrptOn ? "#00d17f" : "";
|
lrptToggleBtn.style.borderColor = lrptOn ? "#00d17f" : "";
|
||||||
lrptToggleBtn.style.color = lrptOn ? "#00d17f" : "";
|
lrptToggleBtn.style.color = lrptOn ? "#00d17f" : "";
|
||||||
}
|
}
|
||||||
|
if (window.updateWxsatLiveState) window.updateWxsatLiveState(update);
|
||||||
const cwAutoEl = document.getElementById("cw-auto");
|
const cwAutoEl = document.getElementById("cw-auto");
|
||||||
const cwWpmEl = document.getElementById("cw-wpm");
|
const cwWpmEl = document.getElementById("cw-wpm");
|
||||||
const cwToneEl = document.getElementById("cw-tone");
|
const cwToneEl = document.getElementById("cw-tone");
|
||||||
|
|||||||
@@ -807,6 +807,23 @@
|
|||||||
<button id="lrpt-decode-toggle-btn" type="button">Enable Meteor LRPT</button>
|
<button id="lrpt-decode-toggle-btn" type="button">Enable Meteor LRPT</button>
|
||||||
<small id="wxsat-status" style="color:var(--text-muted);">Waiting for satellite pass</small>
|
<small id="wxsat-status" style="color:var(--text-muted);">Waiting for satellite pass</small>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- View selector -->
|
||||||
|
<div class="wxsat-view-bar">
|
||||||
|
<button id="wxsat-view-live" class="wxsat-view-btn wxsat-view-active" type="button">Live</button>
|
||||||
|
<button id="wxsat-view-history" class="wxsat-view-btn" type="button">History</button>
|
||||||
|
</div>
|
||||||
|
<!-- Live view -->
|
||||||
|
<div id="wxsat-live-view">
|
||||||
|
<div class="wxsat-live-grid">
|
||||||
|
<div class="wxsat-live-card">
|
||||||
|
<span class="wxsat-live-label">NOAA APT</span>
|
||||||
|
<span id="wxsat-apt-state" class="wxsat-live-value wxsat-state-idle">Idle</span>
|
||||||
|
</div>
|
||||||
|
<div class="wxsat-live-card">
|
||||||
|
<span class="wxsat-live-label">Meteor LRPT</span>
|
||||||
|
<span id="wxsat-lrpt-state" class="wxsat-live-value wxsat-state-idle">Idle</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div style="margin:0.5rem 0;">
|
<div style="margin:0.5rem 0;">
|
||||||
<div style="color:var(--text-muted); font-size:0.82rem; line-height:1.5;">
|
<div style="color:var(--text-muted); font-size:0.82rem; line-height:1.5;">
|
||||||
<strong>NOAA APT</strong> — Automatic Picture Transmission from NOAA-15/18/19 (137 MHz FM).
|
<strong>NOAA APT</strong> — Automatic Picture Transmission from NOAA-15/18/19 (137 MHz FM).
|
||||||
@@ -817,7 +834,33 @@
|
|||||||
Multi-channel CCSDS-framed imagery (APIDs 64–69) with RGB composite output.
|
Multi-channel CCSDS-framed imagery (APIDs 64–69) with RGB composite output.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="wxsat-images"></div>
|
<div id="wxsat-live-latest" style="margin-top:0.5rem;"></div>
|
||||||
|
</div>
|
||||||
|
<!-- History view -->
|
||||||
|
<div id="wxsat-history-view" style="display:none;">
|
||||||
|
<div class="wxsat-history-controls">
|
||||||
|
<input id="wxsat-filter" class="ft8-filter" type="text" placeholder="Filter (e.g. NOAA-18, Meteor, APT)" />
|
||||||
|
<select id="wxsat-sort" class="wxsat-sort-select">
|
||||||
|
<option value="newest">Newest first</option>
|
||||||
|
<option value="oldest">Oldest first</option>
|
||||||
|
</select>
|
||||||
|
<select id="wxsat-type-filter" class="wxsat-sort-select">
|
||||||
|
<option value="all">All types</option>
|
||||||
|
<option value="apt">NOAA APT only</option>
|
||||||
|
<option value="lrpt">Meteor LRPT only</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="wxsat-history-header">
|
||||||
|
<span class="wxsat-col-time">Time</span>
|
||||||
|
<span class="wxsat-col-type">Type</span>
|
||||||
|
<span class="wxsat-col-sat">Satellite</span>
|
||||||
|
<span class="wxsat-col-ch">Channels</span>
|
||||||
|
<span class="wxsat-col-lines">Lines</span>
|
||||||
|
<span class="wxsat-col-link">Image</span>
|
||||||
|
</div>
|
||||||
|
<div id="wxsat-history-list"></div>
|
||||||
|
<small id="wxsat-history-count" style="color:var(--text-muted);font-size:0.75rem;">No images yet</small>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="tab-map" class="tab-panel" style="display:none;">
|
<div id="tab-map" class="tab-panel" style="display:none;">
|
||||||
|
|||||||
@@ -1,10 +1,27 @@
|
|||||||
// --- Weather Satellite Decoder Plugin ---
|
// --- Weather Satellite Decoder Plugin ---
|
||||||
|
// Live view: decoder state, latest image card
|
||||||
|
// History view: filterable table of all decoded images
|
||||||
|
|
||||||
|
// ── DOM references ──────────────────────────────────────────────────
|
||||||
const wxsatStatus = document.getElementById("wxsat-status");
|
const wxsatStatus = document.getElementById("wxsat-status");
|
||||||
const wxsatImagesEl = document.getElementById("wxsat-images");
|
const wxsatLiveView = document.getElementById("wxsat-live-view");
|
||||||
|
const wxsatHistoryView = document.getElementById("wxsat-history-view");
|
||||||
|
const wxsatLiveLatest = document.getElementById("wxsat-live-latest");
|
||||||
|
const wxsatHistoryList = document.getElementById("wxsat-history-list");
|
||||||
|
const wxsatHistoryCount = document.getElementById("wxsat-history-count");
|
||||||
|
const wxsatFilterInput = document.getElementById("wxsat-filter");
|
||||||
|
const wxsatSortSelect = document.getElementById("wxsat-sort");
|
||||||
|
const wxsatTypeFilter = document.getElementById("wxsat-type-filter");
|
||||||
|
const wxsatAptState = document.getElementById("wxsat-apt-state");
|
||||||
|
const wxsatLrptState = document.getElementById("wxsat-lrpt-state");
|
||||||
|
|
||||||
|
// ── State ───────────────────────────────────────────────────────────
|
||||||
let wxsatImageHistory = [];
|
let wxsatImageHistory = [];
|
||||||
const WXSAT_MAX_IMAGES = 20;
|
const WXSAT_MAX_IMAGES = 100;
|
||||||
|
let wxsatFilterText = "";
|
||||||
|
let wxsatActiveView = "live"; // "live" | "history"
|
||||||
|
|
||||||
|
// ── UI scheduler helper ─────────────────────────────────────────────
|
||||||
function scheduleWxsatUi(key, job) {
|
function scheduleWxsatUi(key, job) {
|
||||||
if (typeof window.trxScheduleUiFrameJob === "function") {
|
if (typeof window.trxScheduleUiFrameJob === "function") {
|
||||||
window.trxScheduleUiFrameJob(key, job);
|
window.trxScheduleUiFrameJob(key, job);
|
||||||
@@ -13,48 +30,160 @@ function scheduleWxsatUi(key, job) {
|
|||||||
job();
|
job();
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderWxsatImage(img) {
|
// ── View switching ──────────────────────────────────────────────────
|
||||||
const card = document.createElement("div");
|
const wxsatViewLiveBtn = document.getElementById("wxsat-view-live");
|
||||||
card.className = "wxsat-image-card";
|
const wxsatViewHistoryBtn = document.getElementById("wxsat-view-history");
|
||||||
card.style.cssText =
|
|
||||||
"border:1px solid var(--border-color);border-radius:0.5rem;padding:0.5rem;margin-bottom:0.75rem;background:var(--bg-secondary);";
|
|
||||||
|
|
||||||
const ts = img._ts || new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" });
|
function switchWxsatView(view) {
|
||||||
|
wxsatActiveView = view;
|
||||||
|
if (wxsatLiveView) wxsatLiveView.style.display = view === "live" ? "" : "none";
|
||||||
|
if (wxsatHistoryView) wxsatHistoryView.style.display = view === "history" ? "" : "none";
|
||||||
|
if (wxsatViewLiveBtn) {
|
||||||
|
wxsatViewLiveBtn.classList.toggle("wxsat-view-active", view === "live");
|
||||||
|
}
|
||||||
|
if (wxsatViewHistoryBtn) {
|
||||||
|
wxsatViewHistoryBtn.classList.toggle("wxsat-view-active", view === "history");
|
||||||
|
}
|
||||||
|
if (view === "history") {
|
||||||
|
renderWxsatHistoryTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wxsatViewLiveBtn?.addEventListener("click", () => switchWxsatView("live"));
|
||||||
|
wxsatViewHistoryBtn?.addEventListener("click", () => switchWxsatView("history"));
|
||||||
|
|
||||||
|
// ── Live view: decoder state ────────────────────────────────────────
|
||||||
|
// Updated from app.js render() via window.updateWxsatLiveState
|
||||||
|
window.updateWxsatLiveState = function (update) {
|
||||||
|
if (!wxsatAptState || !wxsatLrptState) return;
|
||||||
|
const aptOn = !!update.wxsat_decode_enabled;
|
||||||
|
const lrptOn = !!update.lrpt_decode_enabled;
|
||||||
|
|
||||||
|
wxsatAptState.textContent = aptOn ? "Listening" : "Idle";
|
||||||
|
wxsatAptState.className = "wxsat-live-value " + (aptOn ? "wxsat-state-listening" : "wxsat-state-idle");
|
||||||
|
wxsatLrptState.textContent = lrptOn ? "Listening" : "Idle";
|
||||||
|
wxsatLrptState.className = "wxsat-live-value " + (lrptOn ? "wxsat-state-listening" : "wxsat-state-idle");
|
||||||
|
};
|
||||||
|
|
||||||
|
function renderWxsatLatestCard() {
|
||||||
|
if (!wxsatLiveLatest) return;
|
||||||
|
if (wxsatImageHistory.length === 0) {
|
||||||
|
wxsatLiveLatest.innerHTML =
|
||||||
|
'<div style="color:var(--text-muted);font-size:0.82rem;">No images decoded yet. Enable a decoder and wait for a satellite pass.</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const img = wxsatImageHistory[0];
|
||||||
const decoder = img._decoder || "unknown";
|
const decoder = img._decoder || "unknown";
|
||||||
|
const typeName = decoder === "lrpt" ? "Meteor LRPT" : "NOAA APT";
|
||||||
const satellite = img.satellite || "";
|
const satellite = img.satellite || "";
|
||||||
const channels = img.channels || "";
|
const channels = img.channels || img.channel_a || "";
|
||||||
const lines = img.line_count || img.mcu_count || 0;
|
const lines = img.line_count || img.mcu_count || 0;
|
||||||
|
const unit = decoder === "lrpt" ? "MCU rows" : "lines";
|
||||||
|
const ts = img._ts || "--";
|
||||||
|
const date = img._tsMs ? new Date(img._tsMs).toLocaleDateString() : "";
|
||||||
|
|
||||||
let metaParts = [`<strong>${decoder === "lrpt" ? "Meteor LRPT" : "NOAA APT"}</strong>`];
|
let meta = [typeName];
|
||||||
if (satellite) metaParts.push(satellite);
|
if (satellite) meta.push(satellite);
|
||||||
if (channels) metaParts.push("ch " + channels);
|
if (channels) meta.push(channels);
|
||||||
metaParts.push(lines + (decoder === "lrpt" ? " MCU rows" : " lines"));
|
meta.push(`${lines} ${unit}`);
|
||||||
metaParts.push(ts);
|
meta.push(`${date} ${ts}`);
|
||||||
|
|
||||||
card.innerHTML =
|
|
||||||
`<div style="font-size:0.82rem;color:var(--text-muted);margin-bottom:0.35rem;">${metaParts.join(" · ")}</div>`;
|
|
||||||
|
|
||||||
|
let html = `<div class="wxsat-latest-card">`;
|
||||||
|
html += `<div class="wxsat-latest-title">Latest decoded image</div>`;
|
||||||
|
html += `<div class="wxsat-latest-meta">${meta.join(" · ")}</div>`;
|
||||||
if (img.path) {
|
if (img.path) {
|
||||||
const link = document.createElement("a");
|
html += `<a href="${img.path}" target="_blank" style="font-size:0.8rem;color:var(--accent);display:inline-block;margin-top:0.25rem;">Download PNG</a>`;
|
||||||
link.href = img.path;
|
}
|
||||||
link.target = "_blank";
|
html += `</div>`;
|
||||||
link.textContent = "Download image";
|
wxsatLiveLatest.innerHTML = html;
|
||||||
link.style.cssText = "font-size:0.8rem;color:var(--accent);";
|
|
||||||
card.appendChild(link);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return card;
|
// ── History view: table ─────────────────────────────────────────────
|
||||||
|
function getFilteredHistory() {
|
||||||
|
let items = wxsatImageHistory;
|
||||||
|
|
||||||
|
// Type filter
|
||||||
|
const typeVal = wxsatTypeFilter ? wxsatTypeFilter.value : "all";
|
||||||
|
if (typeVal === "apt") items = items.filter((i) => i._decoder === "apt");
|
||||||
|
else if (typeVal === "lrpt") items = items.filter((i) => i._decoder === "lrpt");
|
||||||
|
|
||||||
|
// Text filter
|
||||||
|
if (wxsatFilterText) {
|
||||||
|
items = items.filter((i) => {
|
||||||
|
const haystack = [
|
||||||
|
i._decoder === "lrpt" ? "meteor lrpt" : "noaa apt",
|
||||||
|
i.satellite || "",
|
||||||
|
i.channels || "",
|
||||||
|
i.channel_a || "",
|
||||||
|
i.channel_b || "",
|
||||||
|
]
|
||||||
|
.join(" ")
|
||||||
|
.toUpperCase();
|
||||||
|
return haystack.includes(wxsatFilterText);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderWxsatHistory() {
|
// Sort
|
||||||
if (!wxsatImagesEl) return;
|
const sortVal = wxsatSortSelect ? wxsatSortSelect.value : "newest";
|
||||||
|
if (sortVal === "oldest") {
|
||||||
|
items = items.slice().reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderWxsatHistoryRow(img) {
|
||||||
|
const row = document.createElement("div");
|
||||||
|
row.className = "wxsat-history-row";
|
||||||
|
|
||||||
|
const decoder = img._decoder || "unknown";
|
||||||
|
const typeName = decoder === "lrpt" ? "Meteor LRPT" : "NOAA APT";
|
||||||
|
const typeClass = decoder === "lrpt" ? "wxsat-type-lrpt" : "wxsat-type-apt";
|
||||||
|
const ts = img._ts || "--";
|
||||||
|
const date = img._tsMs ? new Date(img._tsMs).toLocaleDateString([], { month: "short", day: "numeric" }) : "";
|
||||||
|
const satellite = img.satellite || "--";
|
||||||
|
const channels = decoder === "lrpt" ? (img.channels || "--") : (img.channel_a && img.channel_b ? `A:${img.channel_a} B:${img.channel_b}` : img.channel_a || "--");
|
||||||
|
const lines = img.line_count || img.mcu_count || 0;
|
||||||
|
const unit = decoder === "lrpt" ? "MCU" : "ln";
|
||||||
|
const link = img.path
|
||||||
|
? `<a href="${img.path}" target="_blank" style="color:var(--accent);">PNG</a>`
|
||||||
|
: "--";
|
||||||
|
|
||||||
|
row.innerHTML = [
|
||||||
|
`<span>${date} ${ts}</span>`,
|
||||||
|
`<span class="wxsat-col-type ${typeClass}">${typeName}</span>`,
|
||||||
|
`<span>${satellite}</span>`,
|
||||||
|
`<span>${channels}</span>`,
|
||||||
|
`<span>${lines} ${unit}</span>`,
|
||||||
|
`<span>${link}</span>`,
|
||||||
|
].join("");
|
||||||
|
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderWxsatHistoryTable() {
|
||||||
|
if (!wxsatHistoryList) return;
|
||||||
|
const items = getFilteredHistory();
|
||||||
const fragment = document.createDocumentFragment();
|
const fragment = document.createDocumentFragment();
|
||||||
for (let i = 0; i < wxsatImageHistory.length; i += 1) {
|
for (let i = 0; i < items.length; i += 1) {
|
||||||
fragment.appendChild(renderWxsatImage(wxsatImageHistory[i]));
|
fragment.appendChild(renderWxsatHistoryRow(items[i]));
|
||||||
|
}
|
||||||
|
wxsatHistoryList.replaceChildren(fragment);
|
||||||
|
|
||||||
|
if (wxsatHistoryCount) {
|
||||||
|
const total = wxsatImageHistory.length;
|
||||||
|
const shown = items.length;
|
||||||
|
wxsatHistoryCount.textContent =
|
||||||
|
total === 0
|
||||||
|
? "No images yet"
|
||||||
|
: shown === total
|
||||||
|
? `${total} image${total === 1 ? "" : "s"}`
|
||||||
|
: `${shown} of ${total} images`;
|
||||||
}
|
}
|
||||||
wxsatImagesEl.replaceChildren(fragment);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Add image to history ────────────────────────────────────────────
|
||||||
function addWxsatImage(img, decoder) {
|
function addWxsatImage(img, decoder) {
|
||||||
const tsMs = Number.isFinite(img.ts_ms) ? Number(img.ts_ms) : Date.now();
|
const tsMs = Number.isFinite(img.ts_ms) ? Number(img.ts_ms) : Date.now();
|
||||||
img._tsMs = tsMs;
|
img._tsMs = tsMs;
|
||||||
@@ -69,10 +198,14 @@ function addWxsatImage(img, decoder) {
|
|||||||
if (wxsatImageHistory.length > WXSAT_MAX_IMAGES) {
|
if (wxsatImageHistory.length > WXSAT_MAX_IMAGES) {
|
||||||
wxsatImageHistory = wxsatImageHistory.slice(0, WXSAT_MAX_IMAGES);
|
wxsatImageHistory = wxsatImageHistory.slice(0, WXSAT_MAX_IMAGES);
|
||||||
}
|
}
|
||||||
scheduleWxsatUi("wxsat-history", () => renderWxsatHistory());
|
|
||||||
|
scheduleWxsatUi("wxsat-latest", () => renderWxsatLatestCard());
|
||||||
|
if (wxsatActiveView === "history") {
|
||||||
|
scheduleWxsatUi("wxsat-history", () => renderWxsatHistoryTable());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server-dispatched callbacks
|
// ── Server callbacks ────────────────────────────────────────────────
|
||||||
window.onServerWxsatImage = function (msg) {
|
window.onServerWxsatImage = function (msg) {
|
||||||
if (wxsatStatus) wxsatStatus.textContent = "Image received (NOAA APT)";
|
if (wxsatStatus) wxsatStatus.textContent = "Image received (NOAA APT)";
|
||||||
addWxsatImage(msg, "apt");
|
addWxsatImage(msg, "apt");
|
||||||
@@ -85,10 +218,17 @@ window.onServerLrptImage = function (msg) {
|
|||||||
|
|
||||||
window.resetWxsatHistoryView = function () {
|
window.resetWxsatHistoryView = function () {
|
||||||
wxsatImageHistory = [];
|
wxsatImageHistory = [];
|
||||||
if (wxsatImagesEl) wxsatImagesEl.innerHTML = "";
|
if (wxsatHistoryList) wxsatHistoryList.innerHTML = "";
|
||||||
|
renderWxsatLatestCard();
|
||||||
|
renderWxsatHistoryTable();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Toggle buttons
|
window.pruneWxsatHistoryView = function () {
|
||||||
|
renderWxsatHistoryTable();
|
||||||
|
renderWxsatLatestCard();
|
||||||
|
};
|
||||||
|
|
||||||
|
// ── Toggle buttons ──────────────────────────────────────────────────
|
||||||
const wxsatDecodeToggleBtn = document.getElementById("wxsat-decode-toggle-btn");
|
const wxsatDecodeToggleBtn = document.getElementById("wxsat-decode-toggle-btn");
|
||||||
wxsatDecodeToggleBtn?.addEventListener("click", async () => {
|
wxsatDecodeToggleBtn?.addEventListener("click", async () => {
|
||||||
try {
|
try {
|
||||||
@@ -109,7 +249,16 @@ lrptDecodeToggleBtn?.addEventListener("click", async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Clear history button
|
// ── Filter / sort event listeners ───────────────────────────────────
|
||||||
|
wxsatFilterInput?.addEventListener("input", () => {
|
||||||
|
wxsatFilterText = wxsatFilterInput.value.trim().toUpperCase();
|
||||||
|
renderWxsatHistoryTable();
|
||||||
|
});
|
||||||
|
|
||||||
|
wxsatSortSelect?.addEventListener("change", () => renderWxsatHistoryTable());
|
||||||
|
wxsatTypeFilter?.addEventListener("change", () => renderWxsatHistoryTable());
|
||||||
|
|
||||||
|
// ── Settings: clear history ─────────────────────────────────────────
|
||||||
document
|
document
|
||||||
.getElementById("settings-clear-wxsat-history")
|
.getElementById("settings-clear-wxsat-history")
|
||||||
?.addEventListener("click", async () => {
|
?.addEventListener("click", async () => {
|
||||||
@@ -122,5 +271,6 @@ document
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initial render
|
// ── Initial render ──────────────────────────────────────────────────
|
||||||
renderWxsatHistory();
|
renderWxsatLatestCard();
|
||||||
|
renderWxsatHistoryTable();
|
||||||
|
|||||||
@@ -4538,3 +4538,30 @@ button:focus-visible, input:focus-visible, select:focus-visible {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* ── Weather Satellite panel ────────────────────────────────────────── */
|
||||||
|
.wxsat-view-bar { display: flex; gap: 0; margin-bottom: 0.75rem; border-bottom: 1px solid var(--border); }
|
||||||
|
.wxsat-view-btn { flex-shrink: 0; background: transparent; border: none; border-bottom: 2px solid transparent; border-radius: 0; padding: 0.3rem 0.9rem; color: var(--text-muted); cursor: pointer; font-size: 0.82rem; }
|
||||||
|
.wxsat-view-active { border-bottom-color: var(--accent-green); color: var(--accent-green); font-weight: 600; }
|
||||||
|
.wxsat-view-btn:hover:not(.wxsat-view-active) { color: var(--text); }
|
||||||
|
.wxsat-live-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; margin-bottom: 0.5rem; }
|
||||||
|
.wxsat-live-card { background: var(--bg-secondary); border: 1px solid var(--border); border-radius: 0.35rem; padding: 0.5rem 0.75rem; display: flex; flex-direction: column; gap: 0.15rem; }
|
||||||
|
.wxsat-live-label { font-size: 0.75rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; }
|
||||||
|
.wxsat-live-value { font-size: 0.9rem; font-weight: 600; }
|
||||||
|
.wxsat-state-idle { color: var(--text-muted); }
|
||||||
|
.wxsat-state-listening { color: var(--accent-green); }
|
||||||
|
.wxsat-state-decoding { color: #f0a020; }
|
||||||
|
.wxsat-history-controls { display: flex; gap: 0.5rem; align-items: center; margin-bottom: 0.5rem; flex-wrap: wrap; }
|
||||||
|
.wxsat-sort-select { background: var(--bg-secondary); border: 1px solid var(--border); border-radius: 0.25rem; color: var(--text); padding: 0.25rem 0.4rem; font-size: 0.82rem; }
|
||||||
|
.wxsat-history-header { display: grid; grid-template-columns: 7rem 5.5rem 9rem 6rem 4.5rem 1fr; gap: 0.25rem; padding: 0.25rem 0.4rem; font-size: 0.75rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.03em; border-bottom: 1px solid var(--border); }
|
||||||
|
.wxsat-history-row { display: grid; grid-template-columns: 7rem 5.5rem 9rem 6rem 4.5rem 1fr; gap: 0.25rem; padding: 0.35rem 0.4rem; font-size: 0.82rem; border-bottom: 1px solid var(--border-faint, rgba(255,255,255,0.04)); }
|
||||||
|
.wxsat-history-row:hover { background: var(--bg-hover, rgba(255,255,255,0.02)); }
|
||||||
|
.wxsat-col-type { font-weight: 500; }
|
||||||
|
.wxsat-type-apt { color: #6ec6ff; }
|
||||||
|
.wxsat-type-lrpt { color: #b39ddb; }
|
||||||
|
.wxsat-latest-card { background: var(--bg-secondary); border: 1px solid var(--border); border-radius: 0.4rem; padding: 0.6rem 0.75rem; }
|
||||||
|
.wxsat-latest-card .wxsat-latest-title { font-size: 0.82rem; font-weight: 600; margin-bottom: 0.25rem; }
|
||||||
|
.wxsat-latest-card .wxsat-latest-meta { font-size: 0.78rem; color: var(--text-muted); }
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.wxsat-live-grid { grid-template-columns: 1fr; }
|
||||||
|
.wxsat-history-header, .wxsat-history-row { grid-template-columns: 5rem 4rem 6rem 4rem 3.5rem 1fr; font-size: 0.75rem; }
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user