diff --git a/web/static/app.js b/web/static/app.js index b51a8f3a..b09bca74 100644 --- a/web/static/app.js +++ b/web/static/app.js @@ -119,11 +119,18 @@ function buildCityList(cities) { sorted.forEach((city) => { const div = document.createElement("div"); div.className = "city-item"; - div.id = `city-item-${city.name.replace(/\s/g, "-")}`; + const cityId = city.name.replace(/\s/g, "-"); + div.id = `city-item-${cityId}`; div.innerHTML = ` - - ${city.display_name} - +
+ + ${city.display_name} + +
+
+ + +
`; div.addEventListener("click", () => { loadCityDetail(city.name); @@ -145,12 +152,32 @@ function setActiveCityItem(cityName) { } } -function updateCityListTemp(cityName, temp, symbol) { - const id = `temp-${cityName.replace(/\s/g, "-")}`; - const el = document.getElementById(id); - if (el) { - el.textContent = `${temp}${symbol}`; - el.classList.add("loaded"); +function updateCityListInfo(cityData) { + const cityName = cityData.name; + const cityId = cityName.replace(/\s/g, "-"); + const temp = + cityData.current?.max_so_far != null && + cityData.current.max_so_far >= (cityData.current.temp || -999) + ? cityData.current.max_so_far + : cityData.current.temp; + + // Update Temperature + const tempEl = document.getElementById(`temp-${cityId}`); + if (tempEl && temp != null) { + tempEl.textContent = `${temp}${cityData.temp_symbol}`; + tempEl.classList.add("loaded"); + } + + // Update Local Time + const timeEl = document.getElementById(`time-${cityId}`); + if (timeEl && cityData.local_time) { + timeEl.textContent = `🕐 ${cityData.local_time}`; + } + + // Update Max Temp Time + const maxEl = document.getElementById(`max-${cityId}`); + if (maxEl && cityData.current?.max_temp_time) { + maxEl.textContent = `峰值 @${cityData.current.max_temp_time}`; } } @@ -188,7 +215,7 @@ async function loadCityDetail(cityName) { const data = await fetchCityDetail(cityName); cityDataCache[cityName] = data; renderPanel(data); - // Update marker temperature + // Update marker and list if (data.current?.temp != null) { const displayTemp = data.current.max_so_far != null && @@ -196,7 +223,7 @@ async function loadCityDetail(cityName) { ? data.current.max_so_far : data.current.temp; updateMarkerTemp(cityName, displayTemp); - updateCityListTemp(cityName, displayTemp, data.temp_symbol); + updateCityListInfo(data); } } catch (e) { console.error(`Failed to load ${cityName}:`, e); @@ -695,7 +722,7 @@ function startAutoRefresh() { ? data.current.max_so_far : data.current.temp; updateMarkerTemp(selectedCity, displayTemp); - updateCityListTemp(selectedCity, displayTemp, data.temp_symbol); + updateCityListInfo(data); } flashLiveBadge(); } catch (e) { @@ -738,7 +765,7 @@ async function loadAllCitiesProgressively(cities) { ? data.current.max_so_far : data.current.temp; updateMarkerTemp(city.name, displayTemp); - updateCityListTemp(city.name, displayTemp, data.temp_symbol); + updateCityListInfo(data); } // 如果恰好在这个时候用户选中了这个城市,顺便刷新面板 diff --git a/web/static/style.css b/web/static/style.css index 7a491ad2..03299415 100644 --- a/web/static/style.css +++ b/web/static/style.css @@ -281,28 +281,62 @@ body { .city-item { display: flex; - align-items: center; - gap: 8px; + flex-direction: column; + gap: 4px; padding: 10px 12px; border-radius: 10px; cursor: pointer; transition: var(--transition); - font-size: 13px; - font-weight: 500; - color: var(--text-secondary); border: 1px solid transparent; } .city-item:hover { background: rgba(99, 102, 241, 0.08); - color: var(--text-primary); border-color: var(--border-glass); } .city-item.active { background: rgba(99, 102, 241, 0.15); - color: var(--text-primary); border-color: var(--accent-blue); } +.city-item-main { + display: flex; + align-items: center; + gap: 8px; + width: 100%; +} + +.city-item .city-name-text { + font-size: 13px; + font-weight: 500; + color: var(--text-primary); +} + +.city-item .city-temp { + margin-left: auto; + font-size: 13px; + font-weight: 700; + color: var(--accent-cyan); + opacity: 0; + transition: var(--transition); +} +.city-item .city-temp.loaded { + opacity: 1; +} + +.city-item-info { + display: flex; + justify-content: space-between; + align-items: center; + padding-left: 16px; /* Align with name text, after the dot */ + font-size: 10px; + color: var(--text-muted); +} + +.city-item .city-max-info { + color: var(--accent-blue); + font-weight: 500; +} + .city-item .risk-dot { width: 8px; height: 8px;