From 75dba7193a2173afb834e6de9ad53a1c31fa7e01 Mon Sep 17 00:00:00 2001 From: Eli Ribble Date: Sat, 7 Feb 2026 05:54:08 +0000 Subject: [PATCH] Finish removal of font awesome --- .../static/js/address-or-report-suggestion.js | 109 ++++++++++-------- scss/custom.scss | 5 + 2 files changed, 63 insertions(+), 51 deletions(-) diff --git a/html/static/js/address-or-report-suggestion.js b/html/static/js/address-or-report-suggestion.js index b7978878..b334a841 100644 --- a/html/static/js/address-or-report-suggestion.js +++ b/html/static/js/address-or-report-suggestion.js @@ -5,7 +5,7 @@ class AddressOrReportInput extends HTMLElement { constructor() { super(); - this.attachShadow({mode: "open" }); + this.attachShadow({ mode: "open" }); this.internals = this.attachInternals(); this.render(); @@ -13,8 +13,10 @@ class AddressOrReportInput extends HTMLElement { this._addresses = []; this._input = this.shadowRoot.querySelector("input"); this._reports = []; - this._suggestionsContainer = this.shadowRoot.querySelector(".suggestions-container"); - + this._suggestionsContainer = this.shadowRoot.querySelector( + ".suggestions-container", + ); + // Bind methods this._handleInput = this._handleInput.bind(this); @@ -32,30 +34,30 @@ class AddressOrReportInput extends HTMLElement { // Lifecycle: when element is removed from the DOM disconnectedCallback() { - this._input.removeEventListener('input', this._handleInput); + this._input.removeEventListener("input", this._handleInput); } // Lifecycle: watch these attributes for changes static get observedAttributes() { - return ['placeholder', 'api-key']; + return ["placeholder", "api-key"]; } // Lifecycle: respond to attribute changes attributeChangedCallback(name, oldValue, newValue) { - if (name === 'placeholder' && this._input) { + if (name === "placeholder" && this._input) { this._input.placeholder = newValue; } - - if (name === 'api-key') { + + if (name === "api-key") { this._apiKey = newValue; } } - + // Properties API get value() { - return this._input ? this._input.value : ''; + return this._input ? this._input.value : ""; } - + set value(val) { if (this._input) { this._input.value = val; @@ -65,42 +67,41 @@ class AddressOrReportInput extends HTMLElement { } } - // Private methods + // Private methods _handleInput(event) { const searchText = event.target.value.trim(); // Clear previous timer clearTimeout(this._debounceTimer); - + // Clear suggestions if input is less than 3 characters if (searchText.length < 3) { - this._suggestionsContainer.innerHTML = ''; + this._suggestionsContainer.innerHTML = ""; return; } - + // Debounce API calls (wait 300ms after typing stops) this._debounceTimer = setTimeout(() => { this._handleSuggestions(searchText); }, 300); - } async _fetchAddressSuggestions(text) { try { const url = `https://api.mapbox.com/search/geocode/v6/forward?q=${encodeURIComponent(text)}&access_token=${this._apiKey}`; - + const response = await fetch(url); const data = await response.json(); return data.features || []; } catch (error) { - console.error('Error fetching geocoding suggestions:', error); + console.error("Error fetching geocoding suggestions:", error); return []; } } async _fetchReportSuggestions(text) { try { - const url = `/report/suggest?r=${text}` + const url = `/report/suggest?r=${text}`; const response = await fetch(url); const data = await response.json(); return data.reports || []; @@ -112,10 +113,10 @@ class AddressOrReportInput extends HTMLElement { async _handleSuggestions(text) { await Promise.all([ - (async() => { + (async () => { this._addresses = await this._fetchAddressSuggestions(text); })(), - (async() => { + (async () => { this._reports = await this._fetchReportSuggestions(text); })(), ]); @@ -124,21 +125,24 @@ class AddressOrReportInput extends HTMLElement { _renderSuggestions(addresses, reports) { console.log("Rendering suggestions", addresses, reports); - const reportElements = reports.map((item, index) => { - const formatted_id = _formatReportID(item.id); - const type_display = _formatReportType(item.type); - return ` + const reportElements = reports + .map((item, index) => { + const formatted_id = _formatReportID(item.id); + const type_display = _formatReportType(item.type); + return `
${formatted_id}
${type_display}
-
` - }).join(""); - const addressElements = addresses.map((item, index) => { - if (item.properties.place_formatted != "") { - return ` + `; + }) + .join(""); + const addressElements = addresses + .map((item, index) => { + if (item.properties.place_formatted != "") { + return `
${item.properties.name || item.properties.full_address}
${item.properties.place_formatted}
-
` - } else { - return ` + `; + } else { + return `
${item.properties.name || item.properties.full_address}
${item.properties.place_formatted}
-
` - } - }).join(""); + `; + } + }) + .join(""); this._suggestionsContainer.innerHTML = reportElements + addressElements; // Add click listeners to suggestions - this.shadowRoot.querySelectorAll('.suggestion-item').forEach(el => { - el.addEventListener('click', e => { + this.shadowRoot.querySelectorAll(".suggestion-item").forEach((el) => { + el.addEventListener("click", (e) => { const type = el.dataset.type; let detail = null; if (type == "report") { @@ -176,23 +181,25 @@ class AddressOrReportInput extends HTMLElement { this.SetValue(detail); // Dispatch custom event } - this.dispatchEvent(new CustomEvent('suggestion-selected', { - bubbles: true, - composed: true, // Allows event to cross shadow DOM boundary - detail: detail, - })); + this.dispatchEvent( + new CustomEvent("suggestion-selected", { + bubbles: true, + composed: true, // Allows event to cross shadow DOM boundary + detail: detail, + }), + ); }); }); } // Initial render of component render() { - const placeholder = this.getAttribute('placeholder') || 'Enter address'; - + const placeholder = this.getAttribute("placeholder") || "Enter address"; + this.shadowRoot.innerHTML = `
- +
@@ -241,14 +248,14 @@ class AddressOrReportInput extends HTMLElement { // Public methods clear() { if (this._input) { - this._input.value = ''; - this._suggestionsContainer.innerHTML = ''; + this._input.value = ""; + this._suggestionsContainer.innerHTML = ""; } } SetValue(suggestion) { this.value = suggestion.properties.full_address; - this._suggestionsContainer.innerHTML = ''; + this._suggestionsContainer.innerHTML = ""; } } @@ -269,4 +276,4 @@ function _formatReportType(type) { } } -customElements.define('address-or-report-input', AddressOrReportInput); +customElements.define("address-or-report-input", AddressOrReportInput); diff --git a/scss/custom.scss b/scss/custom.scss index b9ded3a1..98a952b1 100644 --- a/scss/custom.scss +++ b/scss/custom.scss @@ -38,6 +38,11 @@ $theme-colors: map-merge( $custom-colors ); +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + @import "./bootstrap/scss/bootstrap"; @import "./sidebar.scss";