Improve homepage light theme map

This commit is contained in:
2569718930@qq.com
2026-04-23 05:20:31 +08:00
parent a237f5daaf
commit 7575891a00
2 changed files with 199 additions and 9 deletions
@@ -2394,6 +2394,164 @@
filter: drop-shadow(0 0 8px rgba(34, 211, 238, 0.22));
}
/* ── Light Theme Dashboard Overrides ── */
:global(html.light) .root {
background:
radial-gradient(circle at 22% 12%, rgba(14, 165, 233, 0.16), transparent 28%),
radial-gradient(circle at 78% 0%, rgba(59, 130, 246, 0.12), transparent 24%),
linear-gradient(180deg, #f8fbff 0%, #e7f1fb 100%);
}
:global(html.light) .root :global(.map) {
background: #dfeefa;
border-color: rgba(36, 68, 104, 0.18);
filter: none;
box-shadow:
0 28px 80px rgba(31, 64, 104, 0.18),
inset 0 1px 0 rgba(255, 255, 255, 0.86);
}
:global(html.light) .root :global(.map .leaflet-tile) {
filter: saturate(1.08) contrast(0.98) brightness(1.02);
}
:global(html.light) .weatherAura {
opacity: 0.22;
mix-blend-mode: multiply;
}
:global(html.light) .weatherAuraScrim {
background:
linear-gradient(
180deg,
rgba(248, 252, 255, 0.2) 0%,
rgba(248, 252, 255, 0.08) 42%,
rgba(226, 239, 250, 0.28) 100%
),
radial-gradient(
circle at 50% 58%,
rgba(14, 165, 233, 0.08) 0%,
rgba(14, 165, 233, 0) 52%
);
}
:global(html.light) .root :global(.home-map-title strong),
:global(html.light) .root :global(.home-panel-city h2),
:global(html.light) .root :global(.home-weather-main strong),
:global(html.light) .root :global(.home-weather-stat strong),
:global(html.light) .root :global(.home-deb-card strong),
:global(html.light) .root :global(.home-card-section h3),
:global(html.light) .root :global(.home-summary-card-head strong),
:global(html.light) .root :global(.opportunity-strip-heading strong),
:global(html.light) .root :global(.opportunity-city),
:global(html.light) .root :global(.home-summary-stat b),
:global(html.light) .root :global(.city-item .city-name-text) {
color: #0b1726;
}
:global(html.light) .root :global(.home-map-title span),
:global(html.light) .root :global(.home-panel-subtitle),
:global(html.light) .root :global(.home-weather-sub),
:global(html.light) .root :global(.home-weather-label),
:global(html.light) .root :global(.home-weather-stat span),
:global(html.light) .root :global(.home-weather-stat small),
:global(html.light) .root :global(.home-deb-card small),
:global(html.light) .root :global(.home-card-section h3 small),
:global(html.light) .root :global(.home-summary-stat span),
:global(html.light) .root :global(.opportunity-strip-heading span),
:global(html.light) .root :global(.opportunity-meta),
:global(html.light) .root :global(.city-group-title),
:global(html.light) .root :global(.home-panel-kicker),
:global(html.light) .root :global(.home-panel-airport) {
color: rgba(66, 84, 108, 0.86);
}
:global(html.light) .root :global(.header) {
background: rgba(248, 252, 255, 0.9);
border-bottom-color: rgba(36, 68, 104, 0.14);
box-shadow: 0 12px 34px rgba(31, 64, 104, 0.08);
}
:global(html.light) .root :global(.city-list),
:global(html.light) .root :global(.home-intelligence-panel),
:global(html.light) .root :global(.home-opportunity-strip) {
background:
radial-gradient(circle at 12% 0%, rgba(14, 165, 233, 0.08), transparent 34%),
rgba(248, 252, 255, 0.9);
border-color: rgba(36, 68, 104, 0.16);
box-shadow: 0 28px 70px rgba(31, 64, 104, 0.14);
color: #0b1726;
}
:global(html.light) .root :global(.home-summary-card),
:global(html.light) .root :global(.opportunity-card),
:global(html.light) .root :global(.home-deb-card),
:global(html.light) .root :global(.home-card-section),
:global(html.light) .root :global(.home-metric-card),
:global(html.light) .root :global(.home-forecast-item),
:global(html.light) .root :global(.home-intraday-reports span) {
background:
radial-gradient(circle at 100% 0%, rgba(14, 165, 233, 0.08), transparent 36%),
rgba(255, 255, 255, 0.92);
border-color: rgba(36, 68, 104, 0.14);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.82);
color: #0b1726;
}
:global(html.light) .root :global(.home-weather-hero) {
background:
linear-gradient(135deg, rgba(238, 246, 255, 0.98), rgba(216, 233, 248, 0.92));
border-color: rgba(36, 68, 104, 0.14);
}
:global(html.light) .root :global(.home-card-section.intraday),
:global(html.light) .root :global(.home-card-section.probability) {
background:
radial-gradient(circle at 0% 25%, rgba(14, 165, 233, 0.1), transparent 42%),
rgba(255, 255, 255, 0.92);
}
:global(html.light) .root :global(.home-intraday-chart line) {
stroke: rgba(66, 84, 108, 0.16);
}
:global(html.light) .root :global(.home-intraday-reports strong),
:global(html.light) .root :global(.home-probability-threshold),
:global(html.light) .root :global(.home-market-question strong),
:global(html.light) .root :global(.home-market-metrics strong),
:global(html.light) .root :global(.home-forecast-item strong) {
color: #0b1726;
}
:global(html.light) .root :global(.home-probability-row div),
:global(html.light) .root :global(.home-probability-track) {
background: rgba(37, 57, 82, 0.12);
}
:global(html.light) .root :global(.city-group) {
background: rgba(255, 255, 255, 0.54);
border-color: rgba(36, 68, 104, 0.12);
}
:global(html.light) .root :global(.city-group-header:hover),
:global(html.light) .root :global(.city-item:hover) {
background: rgba(221, 235, 250, 0.86);
}
:global(html.light) .root :global(.city-item.active) {
background:
linear-gradient(90deg, rgba(14, 165, 233, 0.18), rgba(14, 165, 233, 0.06)),
rgba(255, 255, 255, 0.88);
border-color: rgba(14, 165, 233, 0.42);
}
:global(html.light) .root :global(.leaflet-control-attribution),
:global(html.light) .root :global(.leaflet-control-zoom a) {
background: rgba(248, 252, 255, 0.86) !important;
border-color: rgba(36, 68, 104, 0.16) !important;
color: #0b1726 !important;
}
@keyframes home-panel-enter {
from {
opacity: 0;
+41 -9
View File
@@ -34,6 +34,10 @@ const AUTO_NEARBY_MAX_DISTANCE_M = 120000;
const AUTO_NEARBY_IDLE_REFRESH_DELAY_MS = 10_000;
const AUTO_NEARBY_MIN_REFRESH_INTERVAL_MS = 60_000;
const MAP_MAX_ZOOM = 19;
const MAP_TILE_URLS = {
dark: "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
light: "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
} as const;
const CITY_MARKER_DISPLAY_OFFSETS: Record<
string,
{ x: number; y: number; zIndexOffset?: number }
@@ -52,6 +56,16 @@ function getMarkerDisplayOffset(cityName: string) {
};
}
function getMapTileUrl() {
if (
typeof document !== "undefined" &&
document.documentElement.classList.contains("light")
) {
return MAP_TILE_URLS.light;
}
return MAP_TILE_URLS.dark;
}
function pickMarkerTemperature(
snapshot?: Pick<CityDetail, "current" | "temp_symbol"> | CitySummary,
) {
@@ -382,6 +396,7 @@ export function useLeafletMap({
}: UseLeafletMapArgs) {
const containerRef = useRef<HTMLDivElement | null>(null);
const mapRef = useRef<L.Map | null>(null);
const tileLayerRef = useRef<L.TileLayer | null>(null);
const markersRef = useRef<
Record<string, { city: CityListItem; marker: L.Marker }>
>({});
@@ -444,18 +459,16 @@ export function useLeafletMap({
});
L.control.zoom({ position: "bottomright" }).addTo(map);
L.tileLayer(
"https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
{
attribution:
'&copy; <a href="https://www.openstreetmap.org/">OSM</a> &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19,
subdomains: "abcd",
},
).addTo(map);
const tileLayer = L.tileLayer(getMapTileUrl(), {
attribution:
'&copy; <a href="https://www.openstreetmap.org/">OSM</a> &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19,
subdomains: "abcd",
}).addTo(map);
const nearbyLayer = L.layerGroup().addTo(map);
mapRef.current = map;
tileLayerRef.current = tileLayer;
nearbyLayerRef.current = nearbyLayer;
// Track which city we've already moved to for the current selection
@@ -515,11 +528,30 @@ export function useLeafletMap({
map.off("click", handleMapClick);
map.remove();
mapRef.current = null;
tileLayerRef.current = null;
nearbyLayerRef.current = null;
markersRef.current = {};
};
}, []);
useEffect(() => {
const tileLayer = tileLayerRef.current;
if (!tileLayer || typeof MutationObserver === "undefined") return;
const syncMapTheme = () => {
tileLayer.setUrl(getMapTileUrl());
};
syncMapTheme();
const observer = new MutationObserver(syncMapTheme);
observer.observe(document.documentElement, {
attributeFilter: ["class"],
attributes: true,
});
return () => observer.disconnect();
}, []);
// Handle initial view if cities are loaded
useEffect(() => {
const map = mapRef.current;