From 3cbef28b1321b46d71c3cc593e812058b8d4c46a Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Wed, 11 Mar 2026 11:14:03 +0800 Subject: [PATCH] feat: Initialize PolyWeather frontend project with Next.js, including core dependencies, root layout, and a dashboard detail panel. --- frontend/app/layout.tsx | 2 + frontend/components/dashboard/DetailPanel.tsx | 47 +++++++++++++++++-- frontend/package-lock.json | 44 +++++++++++++++++ frontend/package.json | 1 + 4 files changed, 90 insertions(+), 4 deletions(-) diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx index 4ed82a59..1a80efa6 100644 --- a/frontend/app/layout.tsx +++ b/frontend/app/layout.tsx @@ -1,5 +1,6 @@ import type { Metadata } from "next"; import { Analytics } from "@vercel/analytics/react"; +import { SpeedInsights } from "@vercel/speed-insights/next"; import "./globals.css"; export const metadata: Metadata = { @@ -28,6 +29,7 @@ export default function RootLayout({ {children} + ); diff --git a/frontend/components/dashboard/DetailPanel.tsx b/frontend/components/dashboard/DetailPanel.tsx index fe9b42ab..a18067eb 100644 --- a/frontend/components/dashboard/DetailPanel.tsx +++ b/frontend/components/dashboard/DetailPanel.tsx @@ -2,6 +2,7 @@ import { ChartConfiguration } from "chart.js/auto"; import clsx from "clsx"; +import { useEffect, useRef } from "react"; import { ForecastTable } from "@/components/dashboard/PanelSections"; import { useChart } from "@/hooks/useChart"; import { useDashboardStore } from "@/hooks/useDashboardStore"; @@ -127,6 +128,7 @@ export function DetailPanel() { const store = useDashboardStore(); const { locale, t } = useI18n(); const detail = store.selectedDetail; + const panelRef = useRef(null); const isOverlayOpen = Boolean(store.futureModalDate) || store.historyState.isOpen || @@ -139,18 +141,49 @@ export function DetailPanel() { !isOverlayOpen; const profileStats = detail ? getCityProfileStats(detail, locale) : []; const scenery = getCityScenery(detail?.name); + const blurActiveElement = () => { + if (typeof document === "undefined") return; + const active = document.activeElement; + if (active instanceof HTMLElement) { + active.blur(); + } + }; + + useEffect(() => { + const panel = panelRef.current; + if (!panel) return; + + if (!isVisible) { + panel.setAttribute("inert", ""); + if ( + typeof document !== "undefined" && + panel.contains(document.activeElement) + ) { + const active = document.activeElement; + if (active instanceof HTMLElement) { + active.blur(); + } + } + return; + } + + panel.removeAttribute("inert"); + }, [isVisible]); return (