2b1d7c0b65
The dashboard had several oversized orchestration, component, and CSS files that made product-copy changes and mobile/performance work risky. This refactor preserves behavior while splitting scan terminal CSS, opportunity helpers, future forecast panels, history/detail charts, and probability/model sections into smaller ownership boundaries. Constraint: No user-visible version bump because this batch is architecture and performance cleanup, not a release announcement. Rejected: Rewrite dashboard state management in the same batch | too broad for a safe upload after CSS and component splitting. Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep new component/CSS boundaries instead of moving product copy back into the large dashboard files. Tested: npm run build; npm run test:business; git diff --check Not-tested: Browser visual smoke test after push
130 lines
4.2 KiB
TypeScript
130 lines
4.2 KiB
TypeScript
"use client";
|
|
|
|
import clsx from "clsx";
|
|
import {
|
|
formatSignalDirection,
|
|
formatSignalStrength,
|
|
localizedText,
|
|
signalTone,
|
|
} from "./FutureForecastModal.utils";
|
|
|
|
type MeteorologySignal = {
|
|
direction?: string | null;
|
|
label?: string | null;
|
|
label_en?: string | null;
|
|
strength?: string | null;
|
|
summary?: string | null;
|
|
summary_en?: string | null;
|
|
};
|
|
|
|
export function FutureForecastTodayEvidenceGrid({
|
|
airportMetarAnchor,
|
|
confirmationRules,
|
|
invalidationRules,
|
|
locale,
|
|
meteorologySignals,
|
|
modelSummary,
|
|
}: {
|
|
airportMetarAnchor: boolean;
|
|
confirmationRules: string[];
|
|
invalidationRules: string[];
|
|
locale: string;
|
|
meteorologySignals: MeteorologySignal[];
|
|
modelSummary: string;
|
|
}) {
|
|
const fallbackInvalidationRule =
|
|
locale === "en-US"
|
|
? "If observations stop tracking the expected curve, wait for the next refresh."
|
|
: "若实测不再贴近预期曲线,等待下一次刷新确认。";
|
|
const fallbackConfirmationRule =
|
|
locale === "en-US"
|
|
? airportMetarAnchor
|
|
? "Keep watching the next anchor METAR report."
|
|
: "Keep watching the next official anchor observation."
|
|
: airportMetarAnchor
|
|
? "继续观察下一次锚点 METAR 报文。"
|
|
: "继续观察下一次官方锚点观测。";
|
|
|
|
return (
|
|
<div className="future-v2-meteorology-grid">
|
|
<section className="future-modal-section future-v2-evidence-panel">
|
|
<div className="modal-section-heading">
|
|
<div className="modal-section-kicker">
|
|
{locale === "en-US" ? "Evidence chain" : "气象证据链"}
|
|
</div>
|
|
<h3>{locale === "en-US" ? "Signal Contributions" : "信号贡献"}</h3>
|
|
</div>
|
|
<div className="future-v2-evidence-list">
|
|
{meteorologySignals.length > 0 ? (
|
|
meteorologySignals.map((signal, index) => (
|
|
<div
|
|
key={`${signal.label || "signal"}-${index}`}
|
|
className={clsx("future-v2-evidence-row", signalTone(signal))}
|
|
>
|
|
<div className="future-v2-evidence-head">
|
|
<strong>
|
|
{localizedText(locale, signal.label, signal.label_en) || "--"}
|
|
</strong>
|
|
<span>
|
|
{formatSignalDirection(signal.direction, locale)} ·{" "}
|
|
{formatSignalStrength(signal.strength, locale)}
|
|
</span>
|
|
</div>
|
|
<p>
|
|
{localizedText(locale, signal.summary, signal.summary_en) ||
|
|
"--"}
|
|
</p>
|
|
</div>
|
|
))
|
|
) : (
|
|
<div className="future-text-block">
|
|
{locale === "en-US"
|
|
? "Meteorology signals are still loading."
|
|
: "气象信号仍在加载。"}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</section>
|
|
|
|
<section className="future-modal-section future-v2-rule-panel">
|
|
<div className="modal-section-heading">
|
|
<div className="modal-section-kicker">
|
|
{locale === "en-US" ? "Failure modes" : "失效条件"}
|
|
</div>
|
|
<h3>
|
|
{locale === "en-US" ? "What Downgrades the Read" : "什么会让判断降级"}
|
|
</h3>
|
|
</div>
|
|
<ul className="future-v2-rule-list">
|
|
{(invalidationRules.length > 0
|
|
? invalidationRules
|
|
: [fallbackInvalidationRule]
|
|
).map((rule, index) => (
|
|
<li key={`${rule}-${index}`}>{rule}</li>
|
|
))}
|
|
</ul>
|
|
</section>
|
|
|
|
<section className="future-modal-section future-v2-rule-panel">
|
|
<div className="modal-section-heading">
|
|
<div className="modal-section-kicker">
|
|
{locale === "en-US" ? "Confirmation" : "确认条件"}
|
|
</div>
|
|
<h3>
|
|
{locale === "en-US" ? "What Confirms the Path" : "什么会确认主路径"}
|
|
</h3>
|
|
</div>
|
|
<ul className="future-v2-rule-list">
|
|
{(confirmationRules.length > 0
|
|
? confirmationRules
|
|
: [fallbackConfirmationRule]
|
|
).map((rule, index) => (
|
|
<li key={`${rule}-${index}`}>{rule}</li>
|
|
))}
|
|
</ul>
|
|
<div className="future-v2-model-note">{modelSummary}</div>
|
|
</section>
|
|
</div>
|
|
);
|
|
}
|