From 6249a003822c070f7e86e0efcd43a143ec001bb4 Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Wed, 15 Apr 2026 23:51:54 +0800 Subject: [PATCH] Refine dashboard detail panel layout --- frontend/components/dashboard/DetailPanel.tsx | 403 +++++++++++------- .../dashboard/DetailPanelChrome.module.css | 213 +++++++++ .../dashboard/FutureForecastModal.tsx | 180 ++++---- .../components/dashboard/HistoryModal.tsx | 102 +++-- .../dashboard/ModalChrome.module.css | 82 ++++ .../dashboard/PolyWeatherDashboard.tsx | 11 +- 6 files changed, 719 insertions(+), 272 deletions(-) create mode 100644 frontend/components/dashboard/DetailPanelChrome.module.css create mode 100644 frontend/components/dashboard/ModalChrome.module.css diff --git a/frontend/components/dashboard/DetailPanel.tsx b/frontend/components/dashboard/DetailPanel.tsx index 947a661c..5d6e97dc 100644 --- a/frontend/components/dashboard/DetailPanel.tsx +++ b/frontend/components/dashboard/DetailPanel.tsx @@ -17,6 +17,7 @@ import { getCityProfileStats, getRiskBadgeLabel, getTemperatureChartData, + getWeatherSummary, } from "@/lib/dashboard-utils"; function DetailMiniTemperatureChart({ detail }: { detail: CityDetail }) { @@ -154,16 +155,9 @@ export function DetailPanel() { const isProStateLoading = store.proAccess.loading; const panelRef = useRef(null); const [heavyContentReady, setHeavyContentReady] = useState(false); - const isOverlayOpen = - Boolean(store.futureModalDate) || - store.historyState.isOpen; - const isVisible = - store.isPanelOpen && - Boolean(store.selectedCity) && - !isOverlayOpen; - const hasBasicPanelContent = Boolean( - detail || selectedSummary || selectedCityItem, - ); + const isOverlayOpen = Boolean(store.futureModalDate) || store.historyState.isOpen; + const isVisible = store.isPanelOpen && Boolean(store.selectedCity) && !isOverlayOpen; + const hasBasicPanelContent = Boolean(detail || selectedSummary || selectedCityItem); const panelDisplayName = detail?.display_name || selectedSummary?.display_name || @@ -188,6 +182,9 @@ export function DetailPanel() { [detail, locale], ); const scenery = getCityScenery(detail?.name); + const weatherSummary = detail + ? getWeatherSummary(detail, locale) + : { weatherIcon: "", weatherText: "" }; const basicCurrentTemp = selectedSummary?.current?.temp; const basicObsTime = selectedSummary?.current?.obs_time; const basicDeb = selectedSummary?.deb?.prediction; @@ -200,11 +197,35 @@ export function DetailPanel() { selectedCityItem?.airport || selectedSummary?.icao || (locale === "en-US" ? "Airport pending" : "机场待确认"); - const isBasicSummaryLoading = - !detail && !selectedSummary && store.loadingState.cityDetail; + const activeTempSymbol = detail?.temp_symbol || selectedSummary?.temp_symbol || "°C"; + const heroCurrentTemp = detail?.current?.temp ?? basicCurrentTemp; + const heroCurrentTempText = + heroCurrentTemp != null ? `${heroCurrentTemp}${activeTempSymbol}` : "--"; + const heroObsTimeLabel = + detail?.current?.obs_time || + basicObsTime || + (locale === "en-US" ? "Observation pending" : "观测时间待更新"); + const heroDebValue = detail?.deb?.prediction ?? basicDeb; + const heroDebText = + heroDebValue != null + ? `${heroDebValue}${activeTempSymbol}` + : locale === "en-US" + ? "Pending" + : "待更新"; + const heroSettlementLabel = + detail?.current?.settlement_source_label || basicSettlementLabel; + const heroAirportLabel = detail?.risk?.airport || basicAirportLabel; + const heroWeatherText = detail + ? weatherSummary.weatherText + : locale === "en-US" + ? "City snapshot" + : "城市快照"; + const heroWeatherIcon = detail ? weatherSummary.weatherIcon : ""; + const isBasicSummaryLoading = !detail && !selectedSummary && store.loadingState.cityDetail; const shouldShowSyncCard = !detail && (store.loadingState.cityDetail || isProStateLoading || isAuthenticated); + const blurActiveElement = () => { if (typeof document === "undefined") return; const active = document.activeElement; @@ -212,6 +233,7 @@ export function DetailPanel() { active.blur(); } }; + const handleFeatureAccess = (feature: "today" | "history") => { blurActiveElement(); @@ -251,10 +273,7 @@ export function DetailPanel() { if (!isVisible) { panel.setAttribute("inert", ""); - if ( - typeof document !== "undefined" && - panel.contains(document.activeElement) - ) { + if (typeof document !== "undefined" && panel.contains(document.activeElement)) { const active = document.activeElement; if (active instanceof HTMLElement) { active.blur(); @@ -303,10 +322,7 @@ export function DetailPanel() { }, [detail, isVisible]); return ( -