From 99ca0e105e712816229de06abe4995c4a5a8493c Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Wed, 4 Mar 2026 18:39:16 +0800 Subject: [PATCH] feat: Add initial PolyWeather map application with a premium dark theme. --- web/app.py | 5 +++- web/static/app.js | 67 +++++++++++++++++++++++++++++++++++++++++-- web/static/index.html | 16 ++++++----- web/static/style.css | 60 +++++++++++++++++++++++++++++++++++++- 4 files changed, 136 insertions(+), 12 deletions(-) diff --git a/web/app.py b/web/app.py index a8a78609..322f4b3c 100644 --- a/web/app.py +++ b/web/app.py @@ -354,6 +354,8 @@ def _analyze(city: str) -> Dict[str, Any]: if mgm: mgc = mgm.get("current", {}) mgm_data = { + "temp": _sf(mgc.get("temp")), + "time": mgc.get("time"), "feels_like": _sf(mgc.get("feels_like")), "humidity": _sf(mgc.get("humidity")), "wind_dir": _sf(mgc.get("wind_dir")), @@ -462,7 +464,8 @@ def _analyze(city: str) -> Dict[str, Any]: try: proxy = _config.get("proxy") fetch_weather_markets(proxy=proxy, timeout=10) - city_mkts = get_city_markets(city, target_date=local_date_str) + # We don't filter by target_date here, we want ALL active contracts for the city + city_mkts = get_city_markets(city) if city_mkts: result["polymarket"] = { "markets": [ diff --git a/web/static/app.js b/web/static/app.js index f635c347..8fab25d4 100644 --- a/web/static/app.js +++ b/web/static/app.js @@ -435,6 +435,18 @@ function renderHero(data) { parts.push(`๐Ÿ‘๏ธ ${cur.visibility_mi}mi`); } + // MGM info (Ankara specific) + if (data.mgm?.temp != null) { + let mgmTimeStr = ""; + if (data.mgm.time) { + const match = data.mgm.time.match(/T?(\d{2}:\d{2})/); + if (match) mgmTimeStr = ` @${match[1]}`; + } + parts.push( + `โญ MGM ๅฎžๆต‹: ${data.mgm.temp}${sym}${mgmTimeStr}`, + ); + } + // Trend badge const trend = data.trend || {}; if (trend.is_dead_market) { @@ -507,12 +519,29 @@ function renderChart(data) { }); } + // MGM observation point (Ankara specific) + const mgmPoints = new Array(times.length).fill(null); + if (data.mgm?.temp != null && data.mgm?.time) { + const timeMatch = data.mgm.time.match(/T?(\d{2}):(\d{2})/); + if (timeMatch) { + let h = parseInt(timeMatch[1], 10); + const m = parseInt(timeMatch[2], 10); + if (m >= 30) h = (h + 1) % 24; + const hourKey = h.toString().padStart(2, "0") + ":00"; + const idx = times.indexOf(hourKey); + if (idx >= 0) { + mgmPoints[idx] = data.mgm.temp; + } + } + } + const ctx = document.getElementById("tempChart").getContext("2d"); if (tempChart) tempChart.destroy(); const validDebTemps = debTemps.filter((t) => t != null); const validMetar = metarPoints.filter((t) => t != null); - const allVals = [...validDebTemps, ...validMetar]; + const validMgm = mgmPoints.filter((t) => t != null); + const allVals = [...validDebTemps, ...validMetar, ...validMgm]; if (allVals.length === 0) { document.getElementById("chartLegend").textContent = "ๆš‚ๆ— ๆ•ฐๆฎ"; return; @@ -555,11 +584,26 @@ function renderChart(data) { pointHoverRadius: 7, pointStyle: "circle", fill: false, - showLine: false, order: 0, }, ]; + if (validMgm.length > 0) { + datasets.push({ + label: "MGMๅฎžๆต‹", + data: mgmPoints, + borderColor: "#facc15", + backgroundColor: "#facc15", + borderWidth: 0, + pointRadius: 7, + pointHoverRadius: 9, + pointStyle: "star", + fill: false, + showLine: false, + order: -1, // Draw on very top + }); + } + // Add subtle OM reference line if DEB offset is significant if (Math.abs(offset) > 0.3) { datasets.push({ @@ -648,6 +692,9 @@ function renderChart(data) { // Chart legend text const legend = document.getElementById("chartLegend"); const legendParts = []; + if (data.mgm?.temp != null) { + legendParts.push(`MGM: ${data.mgm.temp}${data.temp_symbol}`); + } if (debMax != null && omMax != null && Math.abs(offset) > 0.3) { const sign = offset > 0 ? "+" : ""; legendParts.push(`DEBๅ็งป ${sign}${offset.toFixed(1)}ยฐ vs OM`); @@ -827,16 +874,18 @@ function renderAI(data) { } function renderMarket(data) { + const widget = document.getElementById("marketFloatingWidget"); const container = document.getElementById("marketOdds"); if ( !data.polymarket || !data.polymarket.markets || data.polymarket.markets.length === 0 ) { - container.innerHTML = '
ๆš‚ๆ— ็›ธๅ…ณๅคฉๆฐ”ๅˆ็บฆ
'; + widget.classList.add("hidden"); return; } + widget.classList.remove("hidden"); const { markets, divergence } = data.polymarket; let html = ""; @@ -919,6 +968,13 @@ function closePanel() { const panel = document.getElementById("panel"); panel.classList.remove("visible"); setTimeout(() => panel.classList.add("hidden"), 400); + + // Hide Polymarket widget + const marketWidget = document.getElementById("marketFloatingWidget"); + if (marketWidget) { + marketWidget.classList.add("hidden"); + } + selectedCity = null; setSelectedMarker(null); document @@ -1173,6 +1229,11 @@ document.addEventListener("DOMContentLoaded", async () => { // Panel close document.getElementById("panelClose").addEventListener("click", closePanel); + // Market Widget close + document.getElementById("marketClose").addEventListener("click", () => { + document.getElementById("marketFloatingWidget").classList.add("hidden"); + }); + // Escape key document.addEventListener("keydown", (e) => { if (e.key === "Escape") closePanel(); diff --git a/web/static/index.html b/web/static/index.html index 3c35fca0..44648b9c 100644 --- a/web/static/index.html +++ b/web/static/index.html @@ -131,13 +131,6 @@ - -
-

๐Ÿ“ˆ ๅธ‚ๅœบ่ต”็އ Polymarket

-
-
็‚นๅ‡ปๅŸŽๅธ‚ๅŽๅŠ ่ฝฝ...
-
-
@@ -147,6 +140,15 @@ + + +