"use client"; import { ChartConfiguration } from "chart.js/auto"; import clsx from "clsx"; import { ForecastTable } from "@/components/dashboard/PanelSections"; import { useChart } from "@/hooks/useChart"; import { useDashboardStore } from "@/hooks/useDashboardStore"; import { useI18n } from "@/hooks/useI18n"; import { getCityScenery } from "@/lib/dashboard-scenery"; import { CityDetail } from "@/lib/dashboard-types"; import { getCityProfileStats, getRiskBadgeLabel, getTemperatureChartData, } from "@/lib/dashboard-utils"; function DetailMiniTemperatureChart({ detail }: { detail: CityDetail }) { const { locale, t } = useI18n(); const chartData = getTemperatureChartData(detail, locale); const canvasRef = useChart( () => { if (!chartData) { return { data: { datasets: [], labels: [] }, type: "line", } satisfies ChartConfiguration<"line">; } const forecastPoints = chartData.datasets.hasMgmHourly ? chartData.datasets.mgmHourlyPoints : chartData.datasets.debPast.map( (value, index) => value ?? chartData.datasets.debFuture[index], ); return { data: { datasets: [ { borderColor: chartData.datasets.hasMgmHourly ? "rgba(250, 204, 21, 0.92)" : "rgba(52, 211, 153, 0.86)", borderWidth: 1.8, data: forecastPoints, fill: false, label: chartData.datasets.hasMgmHourly ? locale === "en-US" ? "MGM Forecast" : "MGM 预测" : locale === "en-US" ? "DEB Forecast" : "DEB 预测", pointRadius: 0, spanGaps: true, tension: 0.28, }, { backgroundColor: "#22d3ee", borderColor: "#22d3ee", borderWidth: 0, data: chartData.datasets.metarPoints, fill: false, label: locale === "en-US" ? "METAR Observation" : "METAR 实测", pointHoverRadius: 6, pointRadius: 3.8, showLine: false, }, ], labels: chartData.times, }, options: { interaction: { intersect: false, mode: "index" }, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { backgroundColor: "rgba(15, 23, 42, 0.95)", borderColor: "rgba(34, 211, 238, 0.25)", borderWidth: 1, }, }, responsive: true, scales: { x: { grid: { color: "rgba(255,255,255,0.03)" }, ticks: { callback: (_value, index) => typeof index === "number" && index % 4 === 0 ? chartData.times[index] : "", color: "#64748b", font: { size: 10 }, maxRotation: 0, }, }, y: { grid: { color: "rgba(255,255,255,0.03)" }, max: chartData.max, min: chartData.min, ticks: { callback: (value) => `${value}${detail.temp_symbol || "°C"}`, color: "#64748b", font: { size: 10 }, }, }, }, }, type: "line", } satisfies ChartConfiguration<"line">; }, [chartData, detail.temp_symbol, locale], ); return (
{chartData?.legendText || t("detail.chartLegendEmpty")}
); } export function DetailPanel() { const store = useDashboardStore(); const { locale, t } = useI18n(); const detail = store.selectedDetail; const isOverlayOpen = Boolean(store.futureModalDate) || store.historyState.isOpen || store.isGuideOpen; const isVisible = store.isPanelOpen && Boolean(store.selectedCity) && Boolean(detail) && !store.loadingState.cityDetail && !isOverlayOpen; const profileStats = detail ? getCityProfileStats(detail, locale) : []; const scenery = getCityScenery(detail?.name); return ( ); }