diff --git a/frontend/components/dashboard/Dashboard.module.css b/frontend/components/dashboard/Dashboard.module.css index a6718420..9b536c7a 100644 --- a/frontend/components/dashboard/Dashboard.module.css +++ b/frontend/components/dashboard/Dashboard.module.css @@ -67,12 +67,19 @@ /* ── Map ── */ .root :global(.map) { - width: 100%; - height: 100%; position: absolute; - top: 0; - left: 0; + top: calc(var(--header-height) + 16px); + right: 418px; + bottom: 128px; + left: calc(var(--sidebar-width) + 30px); z-index: 1; + overflow: hidden; + border: 1px solid rgba(34, 211, 238, 0.12); + border-radius: 22px; + background: #020617; + box-shadow: + 0 28px 80px rgba(0, 0, 0, 0.38), + inset 0 1px 0 rgba(255, 255, 255, 0.05); } .weatherAura { @@ -890,6 +897,31 @@ background: rgba(148, 163, 184, 0.1); } +.root :global(.home-top-opportunity-label) { + display: inline-flex; + align-self: flex-start; + align-items: center; + gap: 7px; + padding: 5px 8px; + border: 1px solid rgba(34, 211, 238, 0.18); + border-radius: 999px; + background: rgba(8, 145, 178, 0.1); + color: #67e8f9; + font-size: 10px; + font-weight: 900; + letter-spacing: 0.12em; + text-transform: uppercase; +} + +.root :global(.home-top-opportunity-label::before) { + content: ""; + width: 6px; + height: 6px; + border-radius: 999px; + background: #22c55e; + box-shadow: 0 0 12px rgba(34, 197, 94, 0.72); +} + .root :global(.home-card-titlebar) { display: flex; justify-content: space-between; @@ -1468,6 +1500,10 @@ } @media (max-width: 1360px) { + .root :global(.map) { + right: 18px; + } + .root :global(.home-intelligence-panel) { display: none; } @@ -1478,6 +1514,11 @@ } @media (max-width: 1020px) { + .root :global(.map) { + left: 18px; + bottom: 188px; + } + .root :global(.home-opportunity-strip) { left: 18px; grid-template-columns: 1fr; @@ -1489,6 +1530,13 @@ } @media (max-width: 720px) { + .root :global(.map) { + inset: var(--header-height) 0 0; + border-radius: 0; + border-left: 0; + border-right: 0; + } + .root :global(.home-opportunity-strip) { display: none; } diff --git a/frontend/components/dashboard/PolyWeatherDashboard.tsx b/frontend/components/dashboard/PolyWeatherDashboard.tsx index 6f111272..0a269985 100644 --- a/frontend/components/dashboard/PolyWeatherDashboard.tsx +++ b/frontend/components/dashboard/PolyWeatherDashboard.tsx @@ -2,7 +2,7 @@ import clsx from "clsx"; import dynamic from "next/dynamic"; import Link from "next/link"; -import { useEffect, useMemo } from "react"; +import { useEffect, useMemo, useRef } from "react"; import styles from "./Dashboard.module.css"; import detailChromeStyles from "./DetailPanelChrome.module.css"; import modalChromeStyles from "./ModalChrome.module.css"; @@ -122,7 +122,13 @@ function buildSnapshot( detail?.risk?.level; const hitRate = Number(city.deb_recent_hit_rate ?? 0); const sampleCount = Number(city.deb_recent_sample_count ?? 0); + const edgePercent = Number(detail?.market_scan?.edge_percent); + const normalizedEdge = + Number.isFinite(edgePercent) && Math.abs(edgePercent) <= 1 + ? edgePercent * 100 + : edgePercent; const score = + (Number.isFinite(normalizedEdge) ? 1000 + normalizedEdge * 10 : 0) + (RISK_SCORE[String(tier || "")] || 0) * 100 + hitRate * 100 + Math.min(sampleCount, 60) / 10; @@ -288,6 +294,10 @@ function HomeIntelligencePanel({ snapshots }: { snapshots: CitySnapshot[] }) { × +
+ {locale === "en-US" ? "Today’s Top Opportunity" : "今日最佳机会"} +
+

{summary?.display_name || detail?.display_name || city.display_name}

@@ -520,6 +530,7 @@ function OpportunityStrip({ snapshots }: { snapshots: CitySnapshot[] }) { function DashboardScreen() { const store = useDashboardStore(); const { t } = useI18n(); + const didAutoFocusRef = useRef(false); const activeSummary = store.selectedCity ? store.citySummariesByName[store.selectedCity] || null : null; @@ -581,6 +592,17 @@ function DashboardScreen() { const showHomepageChrome = !store.isPanelOpen && !store.historyState.isOpen && !store.futureModalDate; + useEffect(() => { + if (didAutoFocusRef.current) return; + if (!showHomepageChrome) return; + if (store.selectedCity) return; + const topOpportunity = homepageSnapshots[0]?.city.name; + if (!topOpportunity) return; + + didAutoFocusRef.current = true; + void store.focusCity(topOpportunity); + }, [homepageSnapshots, showHomepageChrome, store]); + return (