From 2aab080dec2905814163f6e3322d7b768ea3b104 Mon Sep 17 00:00:00 2001 From: shmyga Date: Wed, 24 Jun 2026 15:45:15 +0300 Subject: [PATCH] feat(weather): improve weather locations list --- .../route/view/weather/templates/index.html | 59 ++------- static/src/index.ts | 1 + static/src/main.scss | 2 +- static/src/{ => weather}/weather.scss | 0 static/src/weather/weather.ts | 113 ++++++++++++++++++ 5 files changed, 126 insertions(+), 49 deletions(-) rename static/src/{ => weather}/weather.scss (100%) create mode 100644 static/src/weather/weather.ts diff --git a/gallery/easel/route/view/weather/templates/index.html b/gallery/easel/route/view/weather/templates/index.html index 78d8044..aa28342 100644 --- a/gallery/easel/route/view/weather/templates/index.html +++ b/gallery/easel/route/view/weather/templates/index.html @@ -33,66 +33,29 @@ type="submit">{{_("Search")}} +{% if locations %} +
+{% endif %} + {% endblock %} \ No newline at end of file diff --git a/static/src/index.ts b/static/src/index.ts index cd01b14..f0b971c 100644 --- a/static/src/index.ts +++ b/static/src/index.ts @@ -3,6 +3,7 @@ import "./components"; import "./language"; import "./main.scss"; import "./theme"; +import "./weather/weather"; document.addEventListener("DOMContentLoaded", (event) => { const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]'); diff --git a/static/src/main.scss b/static/src/main.scss index 51d728e..6a1a80e 100644 --- a/static/src/main.scss +++ b/static/src/main.scss @@ -4,7 +4,7 @@ @import "./lib/weather-icons/weather-icons"; @import "./widget.scss"; -@import "./weather.scss"; +@import "./weather/weather.scss"; .table.table-compact { td { diff --git a/static/src/weather.scss b/static/src/weather/weather.scss similarity index 100% rename from static/src/weather.scss rename to static/src/weather/weather.scss diff --git a/static/src/weather/weather.ts b/static/src/weather/weather.ts new file mode 100644 index 0000000..97cde50 --- /dev/null +++ b/static/src/weather/weather.ts @@ -0,0 +1,113 @@ +export interface Location { + id: string; + name: string; + provider: string; + country_code: string; + country?: string; + district?: string; + subdistrict?: string; +} + +export class WeatherLocationStorage { + private storageKey: string = "weather:locations"; + + getAll(): Location[] { + const locations = JSON.parse(window.localStorage.getItem(this.storageKey) || "{}"); + return Object.values(locations); + } + + add(location: Location) { + const locations = JSON.parse(window.localStorage.getItem(this.storageKey) || "{}"); + locations[location.id] = location; + window.localStorage.setItem(this.storageKey, JSON.stringify(locations)); + } + + remove(id: string) { + const locations = JSON.parse(window.localStorage.getItem(this.storageKey) || "{}"); + delete locations[id]; + window.localStorage.setItem(this.storageKey, JSON.stringify(locations)); + } +} + +export class WeatherLocationManager { + loadLocations(selector: string) { + const locations = window.weatherLocationStorage.getAll(); + const container = document.querySelector(selector); + if (container) { + container.innerHTML = ""; + for (const location of locations) { + const element = new WeatherLocationElement(); + element.setAttribute("location", JSON.stringify(location)); + element.setAttribute("removable", ""); + container.appendChild(element); + } + } + } +} + +class WeatherLocationElement extends HTMLElement { + static observedAttributes = ["location", "removable"]; + + location: Location | null = null; + + constructor() { + super(); + this.handleClick = this.handleClick.bind(this); + this.handleRemoveClick = this.handleRemoveClick.bind(this); + } + + connectedCallback() { + this.location = JSON.parse(this.getAttribute("location") || "{}"); + this.innerHTML = ` + + + + ${this.location?.name} + + ${this.location?.country}, ${this.location?.district}, ${this.location?.subdistrict} + + + + ✕ + + `; + this.addEventListener("click", this.handleClick); + if (this.hasAttribute("removable")) { + this.querySelector("[data-remove]")?.addEventListener("click", this.handleRemoveClick); + } else { + this.querySelector("[data-remove]")?.remove(); + } + } + + disconnectedCallback() { + this.removeEventListener("click", this.handleClick); + } + + handleClick(event: MouseEvent) { + if (this.location) { + window.weatherLocationStorage.add(this.location); + } + } + + handleRemoveClick(event: MouseEvent) { + event.preventDefault(); + event.stopPropagation(); + if (this.location) { + window.weatherLocationStorage.remove(this.location.id); + } + this.remove(); + } +} + +customElements.define("weather-location", WeatherLocationElement); + +declare global { + interface Window { + weatherLocationStorage: WeatherLocationStorage; + weatherLocationManager: WeatherLocationManager; + } +} + +window.weatherLocationStorage = new WeatherLocationStorage(); +window.weatherLocationManager = new WeatherLocationManager();