From d0c0c44b4074aea2ffe5f02adb487f4d5a9dadb8 Mon Sep 17 00:00:00 2001 From: Viet Ngoc Date: Thu, 14 Nov 2024 22:26:05 +0100 Subject: [PATCH] Squashed commit of the following: commit fe55903df6f75846911dd040c8f7940079740527 Author: Viet Ngoc Date: Thu Nov 14 22:23:44 2024 +0100 refactor: improve search function and optimize results --- README.md | 4 +- package.json | 3 +- scripts/update-readme.js | 3 +- src/components/moon-editor-search.ts | 103 ++++++++++++++------------- src/css/editor.css | 2 +- src/lunar-phase-card.ts | 1 - src/types.ts | 9 +++ 7 files changed, 68 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 6cbc972..28c9450 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,6 @@ - - ### Supported Localization
@@ -60,7 +58,7 @@ | `ru` | Русский | Русский | | `sk` | Slovak | Slovenčina | -
+ ### View options diff --git a/package.json b/package.json index afb88cf..4eb4002 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "@rollup/plugin-terser": "^0.4.4", "@typescript-eslint/eslint-plugin": "^7.15.0", "@typescript-eslint/parser": "^7.15.0", + "country-state-city": "^3.2.1", "devcert": "^1.2.2", "dotenv": "^16.4.5", "eslint": "^8.9.0", @@ -79,4 +80,4 @@ "import-lang": "node scripts/generate-lang-imports.js", "local-copy": "cp dist/lunar-phase-card.js /Volumes/config/www/dashboard-resources/lunar-phase-card.js" } -} \ No newline at end of file +} diff --git a/scripts/update-readme.js b/scripts/update-readme.js index f0b80d5..7f22f92 100644 --- a/scripts/update-readme.js +++ b/scripts/update-readme.js @@ -13,7 +13,7 @@ const updateReadme = () => { const startMarker = '### Supported Localization'; const endMarker = ''; const startIndex = readmeContent.indexOf(startMarker); - const endIndex = readmeContent.indexOf(endMarker) + endMarker.length; + const endIndex = readmeContent.indexOf(endMarker, startIndex); if (startIndex === -1 || endIndex === -1) { console.error('Localization section not found in README.md'); @@ -58,5 +58,4 @@ ${newTableRows} console.log('README.md updated successfully!'); }; -// Run the script updateReadme(); diff --git a/src/components/moon-editor-search.ts b/src/components/moon-editor-search.ts index df0552a..23f8875 100644 --- a/src/components/moon-editor-search.ts +++ b/src/components/moon-editor-search.ts @@ -1,4 +1,6 @@ -import { mdiClose, mdiMagnify } from '@mdi/js'; +import { mdiClose } from '@mdi/js'; +import { ICity } from 'country-state-city'; +import { City } from 'country-state-city'; import { LitElement, TemplateResult, CSSResultGroup, html, nothing, css } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; @@ -16,8 +18,6 @@ export class MoonEditorSearch extends LitElement { @property({ attribute: false }) _editor!: LunarPhaseCardEditor; @state() _searchValue: string = ''; @state() _searchResults: SearchResults[] = []; - @state() _searchResultsVisible = false; - @state() _toastDissmissed = false; static get styles(): CSSResultGroup { return [editorStyles]; @@ -28,15 +28,14 @@ export class MoonEditorSearch extends LitElement { this._handleSearchInput(ev)} - @blur=${() => this._searchLocation()} > - ${this._searchResultsVisible + ${this._searchValue !== '' ? html`` - : html``} + : nothing} `; const infoSuccess = html` `; } - private _handleAlertDismiss(ev: Event): void { - const alert = ev.target as HTMLElement; - alert.style.display = 'none'; - this._toastDissmissed = true; - } - private _renderSearchResults(): TemplateResult | typeof nothing { - if (!this._searchResultsVisible || this._searchResults.length === 0) { - return html`${!this._toastDissmissed - ? html` this._handleAlertDismiss(ev)} - > - You can get the latitude and longitude from the search with query like "London, UK".` - : nothing}`; + if (this._searchResults.length === 0) { + return nothing; } const results = this._searchResults.map((result) => { return html`
  • this._handleSearchResult(result)}> - ${result.display_name} + ${result.display_name || result.name} ${result.countryCode ? `(${result.countryCode})` : ''}
  • `; }); @@ -85,11 +70,18 @@ export class MoonEditorSearch extends LitElement { private _handleSearchResult(result: SearchResults): void { console.log('search result', result); - const { lat, lon, display_name } = result; + const resultCity = { + name: result.display_name || result.name, + latitude: result.lat || result.latitude, + longitude: result.lon || result.longitude, + }; + + const { name, latitude, longitude } = resultCity; + const event = new CustomEvent('location-update', { detail: { - latitude: lat, - longitude: lon, + latitude, + longitude, }, bubbles: true, composed: true, @@ -97,45 +89,58 @@ export class MoonEditorSearch extends LitElement { this.dispatchEvent(event); this._clearSearch(); - const message = `${display_name} [${lat}, ${lon}]`; - this._handleSettingsSuccess(message); + const message = `${name} [${latitude}, ${longitude}]`; + this._setSettingsAlert(message); } - private _handleSettingsSuccess(message: string): void { - const alert = this.shadowRoot?.getElementById('success-alert') as HTMLElement; + private _setSettingsAlert(message: string, error: boolean = false): void { + const alert = this.shadowRoot?.getElementById('success-alert') as Element; if (alert) { alert.innerHTML = message; - alert.style.display = 'block'; + alert.setAttribute('alert-type', error ? 'error' : 'info'); + alert.setAttribute('style', 'display: block;'); + alert.setAttribute('title', error ? '' : 'Location change'); setTimeout(() => { - alert.style.display = 'none'; + alert.setAttribute('style', 'display: none;'); }, ALERT_DURATION); } } - private _handleSearchInput(ev: Event): void { + private async _handleSearchInput(ev: Event): Promise { ev.stopPropagation(); const target = ev.target as HTMLInputElement; this._searchValue = target.value; + await new Promise((resolve) => setTimeout(resolve, 50)); + this._refreshSearchResults(this._searchValue); + } + + private async _refreshSearchResults(searchValue: string): Promise { + const searchValueTrimmed = searchValue.trim(); + let searchResults = this.getMatchingCities(searchValueTrimmed) as ICity[]; + + if (searchResults.length === 0) { + searchResults = await getCoordinates(searchValueTrimmed); + if (searchResults.length === 0) { + this._setSettingsAlert('No results found', true); + } + } + + if (searchResults) { + this._searchResults = searchResults as SearchResults[]; + } + } + + private getMatchingCities(startsWith: string): ICity[] { + const range = 10; + const cities = City.getAllCities(); + cities.sort((a, b) => a.name.localeCompare(b.name)); + const filteredCities = cities.filter((city) => city.name.toLowerCase().startsWith(startsWith.toLowerCase())); + return filteredCities.slice(0, range); } private _clearSearch(): void { console.log('clear search'); this._searchValue = ''; this._searchResults = []; - this._searchResultsVisible = false; - } - - private async _searchLocation(): Promise { - console.log('search location', this._searchValue); - const searchValue = this._searchValue; - if (!searchValue || searchValue === '') { - return; - } - this._toastDissmissed = true; - const results = await getCoordinates(searchValue); - if (results) { - this._searchResults = results; - this._searchResultsVisible = true; - } } } diff --git a/src/css/editor.css b/src/css/editor.css index 68f17ac..afdfb17 100644 --- a/src/css/editor.css +++ b/src/css/editor.css @@ -116,7 +116,7 @@ ul.search-results { padding-right: 0; margin-top: 0; margin-bottom: 0; - max-height: 500px; + max-height: 250px; overflow-y: auto; background-color: var(--divider-color); } diff --git a/src/lunar-phase-card.ts b/src/lunar-phase-card.ts index c8692c0..7bd9f2f 100644 --- a/src/lunar-phase-card.ts +++ b/src/lunar-phase-card.ts @@ -42,7 +42,6 @@ export class LunarPhaseCard extends LitElement { @state() _hass!: HomeAssistant; @property({ attribute: false }) config!: LunarPhaseCardConfig; @property({ type: Object }) protected moon!: Moon; - @state() _activeCard: PageType | null = null; @state() selectedDate: Date | undefined; @state() _refreshInterval: number | undefined; diff --git a/src/types.ts b/src/types.ts index 52631c6..e46ad4b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,3 +1,4 @@ +import { ICity } from 'country-state-city'; // Cutom card helpers: import { LovelaceCardConfig, Themes, HomeAssistant, Theme } from 'custom-card-helpers'; import { HassEntity } from 'home-assistant-js-websocket'; @@ -171,4 +172,12 @@ export type SearchResults = { name: string; lat: number; lon: number; +} & ICity; + +export type ResultItem = SearchResults & { + name: string; + countryCode: string; + stateCode: string; + latitude?: string | null; + longitude?: string | null; };