Tighten homepage weather summaries

This commit is contained in:
2569718930@qq.com
2026-04-23 01:13:25 +08:00
parent c440a59ca9
commit 731d2e5a18
2 changed files with 103 additions and 58 deletions
@@ -1222,10 +1222,10 @@
}
.root :global(.home-deb-card) {
display: grid;
grid-template-columns: minmax(0, 1fr) 120px;
gap: 12px;
align-items: center;
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 10px;
padding: 12px 14px;
}
@@ -1259,13 +1259,11 @@
font-weight: 850;
}
.root :global(.home-deb-card svg),
.root :global(.home-market-metrics svg) {
width: 100%;
height: 42px;
}
.root :global(.home-deb-card polyline),
.root :global(.home-market-metrics polyline) {
fill: none;
stroke: #18e6d4;
@@ -1274,10 +1272,6 @@
stroke-width: 2.2;
}
.root :global(.home-deb-card circle) {
fill: #18e6d4;
}
.root :global(.home-card-section) {
padding: 12px 14px;
}
@@ -1293,7 +1287,7 @@
.root :global(.home-intraday-chart) {
position: relative;
padding: 10px 0 22px;
padding: 10px 0 0;
}
.root :global(.home-intraday-chart svg) {
@@ -1320,21 +1314,6 @@
stroke-width: 1.6;
}
.root :global(.home-intraday-axis) {
position: absolute;
inset: auto 0 0;
height: 18px;
}
.root :global(.home-intraday-axis span) {
position: absolute;
bottom: 0;
transform: translateX(-50%);
color: rgba(148, 163, 184, 0.82);
font-size: 10px;
font-weight: 700;
}
.root :global(.home-intraday-meta) {
color: rgba(148, 163, 184, 0.9);
font-size: 11px;
@@ -1345,6 +1324,41 @@
-webkit-line-clamp: 3;
}
.root :global(.home-card-section.forecast) {
border-color: rgba(99, 102, 241, 0.24);
}
.root :global(.home-forecast-grid) {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 8px;
}
.root :global(.home-forecast-item) {
min-width: 0;
padding: 10px 8px;
border: 1px solid rgba(148, 163, 184, 0.14);
border-radius: 12px;
background: rgba(15, 23, 42, 0.5);
text-align: center;
}
.root :global(.home-forecast-item span) {
display: block;
color: rgba(148, 163, 184, 0.84);
font-size: 10px;
font-weight: 800;
}
.root :global(.home-forecast-item strong) {
display: block;
margin-top: 6px;
color: #f8fafc;
font-size: 16px;
font-weight: 900;
letter-spacing: -0.04em;
}
.root :global(.home-model-stack) {
display: flex;
flex-wrap: wrap;
@@ -222,7 +222,12 @@ type HomeTrendChart = {
forecastPath: string;
legendText: string;
observationDots: Array<{ cx: number; cy: number; key: string }>;
tickLabels: Array<{ key: string; label: string; x: number }>;
};
type HomeForecastDay = {
key: string;
label: string;
maxTemp: number;
};
function projectHomeTrendPoint(
@@ -314,34 +319,56 @@ function buildHomeTrendChart(
key: `${point.labelTime}-${index}`,
};
});
const tickLabels = chartData.tickLabels
.map((label, index) => {
if (!label) return null;
const minutes = Number.parseInt(String(chartData.times[index] || "0").split(":")[0] || "0", 10) * 60;
const projected = projectHomeTrendPoint(
minutes,
chartData.min,
chartData.xMin,
chartData.xMax,
chartData.min,
chartData.max,
);
return {
key: `${label}-${index}`,
label,
x: projected.cx,
};
})
.filter((item): item is { key: string; label: string; x: number } => item != null);
return {
forecastPath,
legendText: chartData.legendText,
observationDots,
tickLabels,
};
}
function buildHomeForecastDays(
detail?: CityDetail | null,
locale = "zh-CN",
): HomeForecastDay[] {
if (!detail) return [];
const todayLabel = locale === "en-US" ? "Today" : "今天";
const tomorrowLabel = locale === "en-US" ? "Tomorrow" : "明天";
const formatter = new Intl.DateTimeFormat(locale === "en-US" ? "en-US" : "zh-CN", {
day: "2-digit",
month: "2-digit",
});
const rows = Array.isArray(detail.forecast?.daily) ? detail.forecast.daily : [];
const byDate = new Map<string, number>();
if (detail.local_date && Number.isFinite(Number(detail.forecast?.today_high))) {
byDate.set(detail.local_date, Number(detail.forecast?.today_high));
}
rows.forEach((row) => {
if (!row?.date || !Number.isFinite(Number(row.max_temp))) return;
if (!byDate.has(row.date)) {
byDate.set(row.date, Number(row.max_temp));
}
});
return [...byDate.entries()].slice(0, 4).map(([date, maxTemp], index) => {
const parsed = new Date(`${date}T00:00:00`);
const label =
index === 0
? todayLabel
: index === 1
? tomorrowLabel
: Number.isNaN(parsed.getTime())
? date
: formatter.format(parsed);
return {
key: date,
label,
maxTemp,
};
});
}
function readNumericField(source: unknown, key: string) {
if (!source || typeof source !== "object") return undefined;
const value = (source as Record<string, unknown>)[key];
@@ -512,6 +539,7 @@ function HomeIntelligencePanel({ snapshots }: { snapshots: CitySnapshot[] }) {
: locale === "en-US"
? "Pro locked"
: "PRO 锁定";
const forecastDays = buildHomeForecastDays(detail, locale);
const keySignals = [
{
active: Number(marketEdge) > 0,
@@ -624,10 +652,6 @@ function HomeIntelligencePanel({ snapshots }: { snapshots: CitySnapshot[] }) {
<strong>{formatTemperature(debPrediction, symbol)}</strong>
<em>{formatDelta(debPrediction, currentTemp, symbol)}</em>
</div>
<svg viewBox="0 0 110 34" aria-hidden="true">
<polyline points="4,26 22,22 38,14 55,20 72,16 88,8 106,10" />
<circle cx="88" cy="8" r="2.5" />
</svg>
</div>
{trendChart ? (
@@ -648,13 +672,6 @@ function HomeIntelligencePanel({ snapshots }: { snapshots: CitySnapshot[] }) {
<circle key={point.key} cx={point.cx} cy={point.cy} r="3.2" />
))}
</svg>
<div className="home-intraday-axis">
{trendChart.tickLabels.map((tick) => (
<span key={tick.key} style={{ left: `${tick.x}px` }}>
{tick.label}
</span>
))}
</div>
</div>
<div className="home-intraday-meta">
{trendChart.legendText ||
@@ -665,6 +682,20 @@ function HomeIntelligencePanel({ snapshots }: { snapshots: CitySnapshot[] }) {
</div>
) : null}
{forecastDays.length ? (
<div className="home-card-section forecast">
<h3>{locale === "en-US" ? "Multi-day forecast" : "多日预报"}</h3>
<div className="home-forecast-grid">
{forecastDays.map((day) => (
<div key={day.key} className="home-forecast-item">
<span>{day.label}</span>
<strong>{formatTemperature(day.maxTemp, symbol)}</strong>
</div>
))}
</div>
</div>
) : null}
<div className="home-card-section">
<h3>{locale === "en-US" ? "Model stack" : "模型栈"}</h3>
<div className="home-model-stack">