aboutsummaryrefslogtreecommitdiffstats
path: root/app/main.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/main.js')
-rw-r--r--app/main.js454
1 files changed, 213 insertions, 241 deletions
diff --git a/app/main.js b/app/main.js
index ef51345..4ccebe0 100644
--- a/app/main.js
+++ b/app/main.js
@@ -1,7 +1,7 @@
-// main.js - Updated with Sidebar class
+// main.js - Updated with Sidebar class and new Dom interface
-import { LeftSidebar, Modal, RightSidebar } from "components";
-import { Dom, DomOptions } from "dom";
+import { BottomBar, LeftSidebar, Modal, RightSidebar } from "components";
+import { Dom } from "dom";
import { MapEl } from "map";
import {
AreaParam,
@@ -20,67 +20,57 @@ export class Init {
#collection = null;
constructor() {
- this.#loadingElement = Dom.div(
- new DomOptions({
- children: [
- Dom.div(
- new DomOptions({
- children: [
- Dom.span(
- "🏠",
- new DomOptions({
- styles: {
- fontSize: "3rem",
- marginBottom: "1rem",
- },
- }),
- ),
- Dom.span(
- "Loading Housing Application...",
- new DomOptions({
- styles: {
- color: "#333",
- fontSize: "1.2rem",
- fontWeight: "500",
- },
- }),
- ),
- Dom.span(
- "Please wait while we load and process the data",
- new DomOptions({
- styles: {
- color: "#666",
- fontSize: "0.9rem",
- marginTop: "0.5rem",
- },
- }),
- ),
- ],
+ this.#loadingElement = Dom.div({
+ children: [
+ Dom.div({
+ children: [
+ Dom.span({
styles: {
- alignItems: "center",
- display: "flex",
- flexDirection: "column",
- textAlign: "center",
+ fontSize: "3rem",
+ marginBottom: "1rem",
},
+ text: "🏠",
}),
- ),
- ],
- styles: {
- alignItems: "center",
- background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
- color: "white",
- display: "flex",
- fontFamily: "Roboto Mono, monospace",
- height: "100%",
- justifyContent: "center",
- left: "0",
- position: "fixed",
- top: "0",
- width: "100%",
- zIndex: "9999",
- },
- }),
- );
+ Dom.span({
+ styles: {
+ color: "#333",
+ fontSize: "1.2rem",
+ fontWeight: "500",
+ },
+ text: "Loading Housing Application...",
+ }),
+ Dom.span({
+ styles: {
+ color: "#666",
+ fontSize: "0.9rem",
+ marginTop: "0.5rem",
+ },
+ text: "Please wait while we load and process the data",
+ }),
+ ],
+ styles: {
+ alignItems: "center",
+ display: "flex",
+ flexDirection: "column",
+ textAlign: "center",
+ },
+ }),
+ ],
+ styles: {
+ alignItems: "center",
+ background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
+ color: "white",
+ display: "flex",
+ fontFamily: "Roboto Mono, monospace",
+ height: "100%",
+ justifyContent: "center",
+ left: "0",
+ position: "fixed",
+ top: "0",
+ width: "100%",
+ zIndex: "9999",
+ },
+ });
document.body.appendChild(this.#loadingElement);
Object.assign(document.body.style, {
@@ -120,86 +110,74 @@ export class Init {
* @param {string} message
*/
static getError(message) {
- return Dom.div(
- new DomOptions({
- children: [
- Dom.div(
- new DomOptions({
- children: [
- Dom.span(
- "❌",
- new DomOptions({
- styles: {
- fontSize: "3rem",
- marginBottom: "1rem",
- },
- }),
- ),
- Dom.span(
- "Application Error",
- new DomOptions({
- styles: {
- color: "#c53030",
- fontSize: "1.5rem",
- fontWeight: "bold",
- marginBottom: "1rem",
- },
- }),
- ),
- Dom.span(
- message,
- new DomOptions({
- styles: {
- color: "#744210",
- fontSize: "1rem",
- lineHeight: "1.5",
- marginBottom: "2rem",
- textAlign: "center",
- },
- }),
- ),
- Dom.button(
- "Refresh Page",
- () => location.reload(),
- new DomOptions({
- styles: {
- background: "#c53030",
- border: "none",
- borderRadius: "6px",
- color: "white",
- cursor: "pointer",
- fontSize: "1rem",
- padding: "0.75rem 1.5rem",
- transition: "background-color 0.2s",
- },
- }),
- ),
- ],
+ return Dom.div({
+ children: [
+ Dom.div({
+ children: [
+ Dom.span({
+ styles: {
+ fontSize: "3rem",
+ marginBottom: "1rem",
+ },
+ text: "❌",
+ }),
+ Dom.span({
styles: {
- alignItems: "center",
- display: "flex",
- flexDirection: "column",
- maxWidth: "400px",
+ color: "#c53030",
+ fontSize: "1.5rem",
+ fontWeight: "bold",
+ marginBottom: "1rem",
+ },
+ text: "Application Error",
+ }),
+ Dom.span({
+ styles: {
+ color: "#744210",
+ fontSize: "1rem",
+ lineHeight: "1.5",
+ marginBottom: "2rem",
textAlign: "center",
},
+ text: message,
}),
- ),
- ],
- styles: {
- alignItems: "center",
- background: "#fed7d7",
- display: "flex",
- fontFamily: "Roboto Mono, monospace",
- height: "100%",
- justifyContent: "center",
- left: "0",
- position: "fixed",
- top: "0",
- width: "100%",
- zIndex: "9999",
- },
- }),
- );
+ Dom.button({
+ onClick: () => location.reload(),
+ styles: {
+ background: "#c53030",
+ border: "none",
+ borderRadius: "6px",
+ color: "white",
+ cursor: "pointer",
+ fontSize: "1rem",
+ padding: "0.75rem 1.5rem",
+ transition: "background-color 0.2s",
+ },
+ text: "Refresh Page",
+ }),
+ ],
+ styles: {
+ alignItems: "center",
+ display: "flex",
+ flexDirection: "column",
+ maxWidth: "400px",
+ textAlign: "center",
+ },
+ }),
+ ],
+ styles: {
+ alignItems: "center",
+ background: "#fed7d7",
+ display: "flex",
+ fontFamily: "Roboto Mono, monospace",
+ height: "100%",
+ justifyContent: "center",
+ left: "0",
+ position: "fixed",
+ top: "0",
+ width: "100%",
+ zIndex: "9999",
+ },
+ });
}
/**
@@ -233,6 +211,8 @@ export class App {
#houseParameter = HouseParameter.price;
/** @type {AreaParam} */
#areaParameter = AreaParam.unemploymentRate;
+ /** @type {BottomBar} */
+ #bottomBar;
/**
* @param {Collection} collection
@@ -242,6 +222,11 @@ export class App {
this.#collection = collection;
this.#filters = filters;
+ this.#bottomBar = new BottomBar({
+ houses: this.#collection.houses.sort((a, b) => b.scores.current - a.scores.current),
+ onHouseClick: (houseId) => this.#showHouseModal(houseId, true),
+ });
+
Object.assign(document.body.style, {
display: "flex",
flexDirection: "column",
@@ -251,51 +236,48 @@ export class App {
});
// Create header with global toggle buttons
- const header = Dom.div(
- new DomOptions({
- children: [
- // Left sidebar toggle button
- Dom.button(
- "☰ Filters",
- () => this.#leftSidebar.toggle(),
- new DomOptions({
- styles: {
- background: "#fff",
- border: "1px solid #ddd",
- borderRadius: "4px",
- cursor: "pointer",
- fontSize: "1rem",
- margin: "0.5rem",
- padding: "0.5rem 1rem",
- },
- }),
- ),
- // Right sidebar toggle button
- Dom.button(
- "⚙️ Weights",
- () => this.#rightSidebar.toggle(),
- new DomOptions({
- styles: {
- background: "#fff",
- border: "1px solid #ddd",
- borderRadius: "4px",
- cursor: "pointer",
- fontSize: "1rem",
- margin: "0.5rem",
- padding: "0.5rem 1rem",
- },
- }),
- ),
- ],
- styles: {
- background: "#f5f5f5",
- borderBottom: "1px solid #ddd",
- display: "flex",
- justifyContent: "space-between",
- padding: "0",
- },
- }),
- );
+ const header = Dom.div({
+ children: [
+ // Left sidebar toggle button
+ Dom.button({
+ onClick: () => this.#leftSidebar.toggle(),
+ styles: {
+ background: "#fff",
+ border: "1px solid #ddd",
+ borderRadius: "4px",
+ cursor: "pointer",
+ fontSize: "1rem",
+ margin: "0.5rem",
+ padding: "0.5rem 1rem",
+ },
+ text: "☰ Filters",
+ }),
+ // Right sidebar toggle button
+ Dom.button({
+ onClick: () => {
+ this.#bottomBar.show();
+ this.#rightSidebar.toggle();
+ },
+ styles: {
+ background: "#fff",
+ border: "1px solid #ddd",
+ borderRadius: "4px",
+ cursor: "pointer",
+ fontSize: "1rem",
+ margin: "0.5rem",
+ padding: "0.5rem 1rem",
+ },
+ text: "⚙️ Weights",
+ }),
+ ],
+ styles: {
+ background: "#f5f5f5",
+ borderBottom: "1px solid #ddd",
+ display: "flex",
+ justifyContent: "space-between",
+ padding: "0",
+ },
+ });
this.#leftSidebar = new LeftSidebar({
allHouses: this.#collection.houses,
@@ -339,55 +321,52 @@ export class App {
areaParameter: this.#areaParameter,
collection: this.#collection,
houseParameter: this.#houseParameter,
+ /** @param {string} houseId @param {boolean} persistent */
onHouseClick: (houseId, persistent) => this.#showHouseModal(houseId, persistent),
+ /** @param {string} houseId @param {boolean} hide */
onHouseHover: (houseId, hide) => {
- hide ? this.#modal?.hide() : this.#showHouseModal(houseId, false);
+ hide ? this.#modal?.remove() : this.#showHouseModal(houseId, false);
},
});
this.#stats = App.#createStats(this.#collection.houses, this.#filters);
document.body.appendChild(
- Dom.div(
- new DomOptions({
- children: [
- header,
- Dom.div(
- new DomOptions({
- children: [
- this.#leftSidebar.render(),
- Dom.div(
- new DomOptions({
- children: [this.#map.svg, this.#stats],
- id: "map-container",
- styles: {
- display: "flex",
- flex: "1",
- flexDirection: "column",
- minWidth: "0",
- },
- }),
- ),
- this.#rightSidebar.render(),
- ],
- id: "main-content",
+ Dom.div({
+ children: [
+ header,
+ Dom.div({
+ children: [
+ this.#leftSidebar.render(),
+ Dom.div({
+ children: [this.#map.svg, this.#stats],
+ id: "map-container",
styles: {
display: "flex",
flex: "1",
- height: "calc(100vh - 60px)",
- overflow: "hidden",
+ flexDirection: "column",
+ minWidth: "0",
},
}),
- ),
- ],
- id: "main",
- styles: {
- display: "flex",
- flexDirection: "column",
- height: "100vh",
- },
- }),
- ),
+ this.#rightSidebar.render(),
+ this.#bottomBar.render(),
+ ],
+ id: "main-content",
+ styles: {
+ display: "flex",
+ flex: "1",
+ height: "calc(100vh - 60px)",
+ overflow: "hidden",
+ },
+ }),
+ ],
+ id: "main",
+ styles: {
+ display: "flex",
+ flexDirection: "column",
+ height: "100vh",
+ },
+ }),
);
}
@@ -430,11 +409,6 @@ export class App {
}
/**
- * Apply filters and recalculate scores
- */
- #applyFiltersAndScoring() {}
-
- /**
* Create statistics display
* @param {House[]} houses
* @param {Filters} filters
@@ -446,24 +420,22 @@ export class App {
? Math.round(filtered.reduce((s, h) => s + h.scores.current, 0) / filtered.length)
: 0;
- return Dom.div(
- new DomOptions({
- children: [
- Dom.strong(`${filtered.length.toString()}/${houses.length}`),
- Dom.span(" houses shown • Average score: "),
- Dom.strong(averageScore.toString()),
- Dom.span(" • Use weights sliders to adjust scoring"),
- ],
- id: "stats",
- styles: {
- background: "#fff",
- borderTop: "1px solid #ddd",
- flexShrink: "0",
- fontSize: "0.95rem",
- padding: "0.75rem 1rem",
- },
- }),
- );
+ return Dom.div({
+ children: [
+ Dom.strong({ text: `${filtered.length.toString()}/${houses.length}` }),
+ Dom.span({ text: " houses shown • Average score: " }),
+ Dom.strong({ text: averageScore.toString() }),
+ Dom.span({ text: " • Use weights sliders to adjust scoring" }),
+ ],
+ id: "stats",
+ styles: {
+ background: "#fff",
+ borderTop: "1px solid #ddd",
+ flexShrink: "0",
+ fontSize: "0.95rem",
+ padding: "0.75rem 1rem",
+ },
+ });
}
}