Spaces:
Sleeping
Sleeping
feat: compact panel, map overlay stat+legend, 3x2 radio grid, section explore fix
Browse files- Wider panel (340px), compact spacing, no scrollbar
- Move stat card + color scale to floating map overlay (top-left)
- Radio buttons in 3x2 grid instead of vertical list
- Legend simplified to min/max only (removed confusing mid value)
- Fix section explore list: call updateExploreList after section data loads
- Remove property type filter section from panel
- static/app.js +5 -2
- static/index.html +15 -19
- static/style.css +51 -33
static/app.js
CHANGED
|
@@ -439,7 +439,11 @@ async function loadVisibleSections() {
|
|
| 439 |
}
|
| 440 |
}
|
| 441 |
await Promise.all(loadPromises);
|
| 442 |
-
if (changed)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 443 |
} finally {
|
| 444 |
_sectionLoadPending = false;
|
| 445 |
}
|
|
@@ -561,7 +565,6 @@ function updateSectionColors() {
|
|
| 561 |
|
| 562 |
function updateLegend(min, mid, max) {
|
| 563 |
document.getElementById("legend-min").textContent = formatPrice(min);
|
| 564 |
-
document.getElementById("legend-mid").textContent = formatPrice(mid);
|
| 565 |
document.getElementById("legend-max").textContent = formatPrice(max);
|
| 566 |
}
|
| 567 |
|
|
|
|
| 439 |
}
|
| 440 |
}
|
| 441 |
await Promise.all(loadPromises);
|
| 442 |
+
if (changed) {
|
| 443 |
+
updateSectionColors();
|
| 444 |
+
updateExploreList();
|
| 445 |
+
updateDynamicStat();
|
| 446 |
+
}
|
| 447 |
} finally {
|
| 448 |
_sectionLoadPending = false;
|
| 449 |
}
|
|
|
|
| 565 |
|
| 566 |
function updateLegend(min, mid, max) {
|
| 567 |
document.getElementById("legend-min").textContent = formatPrice(min);
|
|
|
|
| 568 |
document.getElementById("legend-max").textContent = formatPrice(max);
|
| 569 |
}
|
| 570 |
|
static/index.html
CHANGED
|
@@ -19,16 +19,7 @@
|
|
| 19 |
<button class="theme-toggle" id="theme-toggle" title="Toggle light/dark mode">☾</button>
|
| 20 |
</div>
|
| 21 |
|
| 22 |
-
<!--
|
| 23 |
-
<div class="panel-section">
|
| 24 |
-
<div class="country-stat">
|
| 25 |
-
<span id="stat-label" class="country-label">National Average</span>
|
| 26 |
-
<span id="stat-price" class="country-price">—</span>
|
| 27 |
-
<span id="stat-detail" class="stat-detail"></span>
|
| 28 |
-
</div>
|
| 29 |
-
</div>
|
| 30 |
-
|
| 31 |
-
<!-- Map level (radio buttons) -->
|
| 32 |
<div class="panel-section">
|
| 33 |
<span class="section-label">Map Level</span>
|
| 34 |
<div class="level-radios">
|
|
@@ -70,7 +61,7 @@
|
|
| 70 |
</div>
|
| 71 |
</div>
|
| 72 |
|
| 73 |
-
<!-- Explore: search + dynamic top
|
| 74 |
<div class="panel-section explore-section">
|
| 75 |
<div class="explore-header">
|
| 76 |
<span class="section-label" id="explore-title">Top Cities</span>
|
|
@@ -91,14 +82,19 @@
|
|
| 91 |
|
| 92 |
<!-- Map -->
|
| 93 |
<div id="map">
|
| 94 |
-
<!-- Floating
|
| 95 |
-
<div id="
|
| 96 |
-
<
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
<span id="
|
| 100 |
-
|
| 101 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
</div>
|
| 103 |
</div>
|
| 104 |
</div>
|
|
|
|
| 19 |
<button class="theme-toggle" id="theme-toggle" title="Toggle light/dark mode">☾</button>
|
| 20 |
</div>
|
| 21 |
|
| 22 |
+
<!-- Map level (radio buttons 3x2 grid) -->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
<div class="panel-section">
|
| 24 |
<span class="section-label">Map Level</span>
|
| 25 |
<div class="level-radios">
|
|
|
|
| 61 |
</div>
|
| 62 |
</div>
|
| 63 |
|
| 64 |
+
<!-- Explore: search + dynamic top list -->
|
| 65 |
<div class="panel-section explore-section">
|
| 66 |
<div class="explore-header">
|
| 67 |
<span class="section-label" id="explore-title">Top Cities</span>
|
|
|
|
| 82 |
|
| 83 |
<!-- Map -->
|
| 84 |
<div id="map">
|
| 85 |
+
<!-- Floating overlay: stat + legend -->
|
| 86 |
+
<div id="map-overlay" class="map-overlay">
|
| 87 |
+
<div class="country-stat">
|
| 88 |
+
<span id="stat-label" class="country-label">National Average</span>
|
| 89 |
+
<span id="stat-price" class="country-price">—</span>
|
| 90 |
+
<span id="stat-detail" class="stat-detail"></span>
|
| 91 |
+
</div>
|
| 92 |
+
<div id="legend">
|
| 93 |
+
<div class="legend-bar"></div>
|
| 94 |
+
<div class="legend-labels">
|
| 95 |
+
<span id="legend-min">—</span>
|
| 96 |
+
<span id="legend-max">—</span>
|
| 97 |
+
</div>
|
| 98 |
</div>
|
| 99 |
</div>
|
| 100 |
</div>
|
static/style.css
CHANGED
|
@@ -30,15 +30,15 @@ body {
|
|
| 30 |
|
| 31 |
/* ---- Left Panel ---- */
|
| 32 |
#panel {
|
| 33 |
-
width:
|
| 34 |
-
min-width:
|
| 35 |
height: 100vh;
|
| 36 |
overflow-y: auto;
|
| 37 |
background: white;
|
| 38 |
-
padding: 16px;
|
| 39 |
display: flex;
|
| 40 |
flex-direction: column;
|
| 41 |
-
gap:
|
| 42 |
border-right: 1px solid #d2d2d7;
|
| 43 |
}
|
| 44 |
|
|
@@ -92,19 +92,19 @@ body {
|
|
| 92 |
gap: 4px;
|
| 93 |
}
|
| 94 |
|
| 95 |
-
/* ---- Level Radio Buttons ---- */
|
| 96 |
.level-radios {
|
| 97 |
-
display:
|
| 98 |
-
|
| 99 |
-
gap: 2px;
|
| 100 |
}
|
| 101 |
|
| 102 |
.level-radio {
|
| 103 |
display: flex;
|
| 104 |
align-items: center;
|
| 105 |
-
gap:
|
| 106 |
-
padding:
|
| 107 |
-
border-radius:
|
| 108 |
cursor: pointer;
|
| 109 |
font-size: 0.8rem;
|
| 110 |
font-weight: 500;
|
|
@@ -395,8 +395,8 @@ body {
|
|
| 395 |
}
|
| 396 |
|
| 397 |
/* ---- Legend ---- */
|
| 398 |
-
/* ---- Floating Map
|
| 399 |
-
.map-
|
| 400 |
position: absolute;
|
| 401 |
top: 12px;
|
| 402 |
left: 12px;
|
|
@@ -404,33 +404,51 @@ body {
|
|
| 404 |
background: rgba(255, 255, 255, 0.92);
|
| 405 |
backdrop-filter: blur(8px);
|
| 406 |
border-radius: 10px;
|
| 407 |
-
padding:
|
| 408 |
-
min-width:
|
| 409 |
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
|
|
|
|
|
|
|
|
|
|
| 410 |
}
|
| 411 |
|
| 412 |
-
.
|
| 413 |
-
|
| 414 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 415 |
text-transform: uppercase;
|
| 416 |
letter-spacing: 0.5px;
|
| 417 |
color: #86868b;
|
| 418 |
-
|
| 419 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 420 |
}
|
| 421 |
|
| 422 |
.legend-bar {
|
| 423 |
-
height:
|
| 424 |
-
border-radius:
|
| 425 |
background: linear-gradient(to right, #028758, #FFF64E, #CC000A);
|
| 426 |
}
|
| 427 |
|
| 428 |
.legend-labels {
|
| 429 |
display: flex;
|
| 430 |
justify-content: space-between;
|
| 431 |
-
font-size: 0.
|
| 432 |
color: #86868b;
|
| 433 |
-
margin-top:
|
| 434 |
}
|
| 435 |
|
| 436 |
/* ---- Country Stat ---- */
|
|
@@ -775,19 +793,19 @@ body.dark-mode .cb-item-price {
|
|
| 775 |
|
| 776 |
/* Dark mode stat */
|
| 777 |
body.dark-mode .country-stat {
|
| 778 |
-
background:
|
| 779 |
}
|
| 780 |
|
| 781 |
body.dark-mode .country-label {
|
| 782 |
-
color: #
|
| 783 |
}
|
| 784 |
|
| 785 |
-
body.dark-mode
|
| 786 |
color: #ffffff;
|
| 787 |
}
|
| 788 |
|
| 789 |
body.dark-mode .stat-detail {
|
| 790 |
-
color: #
|
| 791 |
}
|
| 792 |
|
| 793 |
/* Dark mode price inputs */
|
|
@@ -818,18 +836,18 @@ body.dark-mode .range-container input[type="range"]::-moz-range-thumb {
|
|
| 818 |
border-color: #2a2a2a;
|
| 819 |
}
|
| 820 |
|
| 821 |
-
/* Dark mode
|
| 822 |
-
body.dark-mode .map-
|
| 823 |
background: rgba(36, 36, 36, 0.92);
|
| 824 |
box-shadow: 0 2px 8px rgba(0,0,0,0.4);
|
| 825 |
}
|
| 826 |
|
| 827 |
-
body.dark-mode .
|
| 828 |
-
color: #
|
| 829 |
}
|
| 830 |
|
| 831 |
body.dark-mode .legend-labels {
|
| 832 |
-
color: #
|
| 833 |
}
|
| 834 |
|
| 835 |
/* Dark mode count pills */
|
|
|
|
| 30 |
|
| 31 |
/* ---- Left Panel ---- */
|
| 32 |
#panel {
|
| 33 |
+
width: 340px;
|
| 34 |
+
min-width: 340px;
|
| 35 |
height: 100vh;
|
| 36 |
overflow-y: auto;
|
| 37 |
background: white;
|
| 38 |
+
padding: 14px 16px;
|
| 39 |
display: flex;
|
| 40 |
flex-direction: column;
|
| 41 |
+
gap: 8px;
|
| 42 |
border-right: 1px solid #d2d2d7;
|
| 43 |
}
|
| 44 |
|
|
|
|
| 92 |
gap: 4px;
|
| 93 |
}
|
| 94 |
|
| 95 |
+
/* ---- Level Radio Buttons (3x2 grid) ---- */
|
| 96 |
.level-radios {
|
| 97 |
+
display: grid;
|
| 98 |
+
grid-template-columns: repeat(3, 1fr);
|
| 99 |
+
gap: 2px 6px;
|
| 100 |
}
|
| 101 |
|
| 102 |
.level-radio {
|
| 103 |
display: flex;
|
| 104 |
align-items: center;
|
| 105 |
+
gap: 6px;
|
| 106 |
+
padding: 5px 6px;
|
| 107 |
+
border-radius: 6px;
|
| 108 |
cursor: pointer;
|
| 109 |
font-size: 0.8rem;
|
| 110 |
font-weight: 500;
|
|
|
|
| 395 |
}
|
| 396 |
|
| 397 |
/* ---- Legend ---- */
|
| 398 |
+
/* ---- Floating Map Overlay (stat + legend) ---- */
|
| 399 |
+
.map-overlay {
|
| 400 |
position: absolute;
|
| 401 |
top: 12px;
|
| 402 |
left: 12px;
|
|
|
|
| 404 |
background: rgba(255, 255, 255, 0.92);
|
| 405 |
backdrop-filter: blur(8px);
|
| 406 |
border-radius: 10px;
|
| 407 |
+
padding: 12px 16px;
|
| 408 |
+
min-width: 200px;
|
| 409 |
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
|
| 410 |
+
display: flex;
|
| 411 |
+
flex-direction: column;
|
| 412 |
+
gap: 8px;
|
| 413 |
}
|
| 414 |
|
| 415 |
+
.map-overlay .country-stat {
|
| 416 |
+
background: none;
|
| 417 |
+
border-radius: 0;
|
| 418 |
+
padding: 0;
|
| 419 |
+
text-align: left;
|
| 420 |
+
}
|
| 421 |
+
|
| 422 |
+
.map-overlay .country-label {
|
| 423 |
+
font-size: 0.65rem;
|
| 424 |
text-transform: uppercase;
|
| 425 |
letter-spacing: 0.5px;
|
| 426 |
color: #86868b;
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
.map-overlay .country-price {
|
| 430 |
+
font-size: 1.3rem;
|
| 431 |
+
font-weight: 700;
|
| 432 |
+
color: #1d1d1f;
|
| 433 |
+
}
|
| 434 |
+
|
| 435 |
+
.map-overlay .stat-detail {
|
| 436 |
+
font-size: 0.65rem;
|
| 437 |
+
color: #86868b;
|
| 438 |
}
|
| 439 |
|
| 440 |
.legend-bar {
|
| 441 |
+
height: 8px;
|
| 442 |
+
border-radius: 4px;
|
| 443 |
background: linear-gradient(to right, #028758, #FFF64E, #CC000A);
|
| 444 |
}
|
| 445 |
|
| 446 |
.legend-labels {
|
| 447 |
display: flex;
|
| 448 |
justify-content: space-between;
|
| 449 |
+
font-size: 0.65rem;
|
| 450 |
color: #86868b;
|
| 451 |
+
margin-top: 2px;
|
| 452 |
}
|
| 453 |
|
| 454 |
/* ---- Country Stat ---- */
|
|
|
|
| 793 |
|
| 794 |
/* Dark mode stat */
|
| 795 |
body.dark-mode .country-stat {
|
| 796 |
+
background: none;
|
| 797 |
}
|
| 798 |
|
| 799 |
body.dark-mode .country-label {
|
| 800 |
+
color: #999;
|
| 801 |
}
|
| 802 |
|
| 803 |
+
body.dark-mode .country-price {
|
| 804 |
color: #ffffff;
|
| 805 |
}
|
| 806 |
|
| 807 |
body.dark-mode .stat-detail {
|
| 808 |
+
color: #999;
|
| 809 |
}
|
| 810 |
|
| 811 |
/* Dark mode price inputs */
|
|
|
|
| 836 |
border-color: #2a2a2a;
|
| 837 |
}
|
| 838 |
|
| 839 |
+
/* Dark mode map overlay */
|
| 840 |
+
body.dark-mode .map-overlay {
|
| 841 |
background: rgba(36, 36, 36, 0.92);
|
| 842 |
box-shadow: 0 2px 8px rgba(0,0,0,0.4);
|
| 843 |
}
|
| 844 |
|
| 845 |
+
body.dark-mode .map-overlay .country-price {
|
| 846 |
+
color: #ffffff;
|
| 847 |
}
|
| 848 |
|
| 849 |
body.dark-mode .legend-labels {
|
| 850 |
+
color: #999;
|
| 851 |
}
|
| 852 |
|
| 853 |
/* Dark mode count pills */
|