HERE Maps Adress Search
UPDATED: | POSTED: | by Stefan Schüttenkopf
Requirements
✓ HERE Maps API KeyThis sample gives you the possibility to use HERE Maps address search in your Browser Application respectively within your Dashboard application
Result of the implementation of the code snippet should contain the following points and should look like the following screenshot:
✓ Input field for the adress✓ Different font sizes for name / adress
✓ Setting the number of maximum results
✓ Visualize the result as a pin
Custom Script
Browser JS
import { Bounds } from '@luciad/ria/shape/Bounds';
import { CoordinateReference } from '@luciad/ria/reference/CoordinateReference';
import * as ReferenceProvider from '@luciad/ria/reference/ReferenceProvider';
import * as TransformationFactory from '@luciad/ria/transformation/TransformationFactory';
import { Feature } from '@luciad/ria/model/feature/Feature';
import { FeatureModel } from '@luciad/ria/model/feature/FeatureModel';
import { MemoryStore } from '@luciad/ria/model/store/MemoryStore';
import * as ShapeFactory from '@luciad/ria/shape/ShapeFactory';
import { BasicFeaturePainter } from '@luciad/ria/view/feature/BasicFeaturePainter';
import { FeatureLayer } from '@luciad/ria/view/feature/FeatureLayer';
import { OcclusionMode } from '@luciad/ria/view/style/OcclusionMode';
const wgs84Ref = ReferenceProvider.getReference('EPSG:4326');
const mapToWgs84Transformation = TransformationFactory.createTransformation(window.map.reference, wgs84Ref);
const map = window.map;
const MAX_RESULTS = 10;
function showPointOfInterestLayer(name: string, label: string, visible: boolean, coords: number[], ref: CoordinateReference, fitBounds: any) {
const oldLayer = map.layerTree.findLayerById(name);
oldLayer && map.layerTree.removeChild(oldLayer);
const location = ShapeFactory.createPoint(ref, [coords[1], coords[0]]);
location.z = 0;
let wgs84Bounds: Bounds;
//If HERE sends boundingbox, use it. Else create 1km GeoBuffer around point as bounding box to fit to.
if(fitBounds && fitBounds.west) {
wgs84Bounds = ShapeFactory.createBounds(wgs84Ref, [fitBounds.west, fitBounds.east - fitBounds.west, fitBounds.south, fitBounds.north - fitBounds.south]);
} else {
const geoBuffer = ShapeFactory.createGeoBuffer(wgs84Ref, ShapeFactory.createPolyline(wgs84Ref, [location]), 1000);
wgs84Bounds = geoBuffer.bounds;
}
map.mapNavigator.fit({
bounds: wgs84Bounds,
animate: false
});
const pHeight = ShapeFactory.createPoint(ref, [location.x, location.y, location.z + 50]);
const verticalLine = ShapeFactory.createPolyline(ref, [location, pHeight]);
const imagePoint = ShapeFactory.createPoint(ref, [location.x, location.y, location.z + 50]);
const feature = new Feature(location, {}, 1);
const store = new MemoryStore({
data: [feature]
});
const featureModel = new FeatureModel(store, { reference: ref });
const icon3dStylePainter = new BasicFeaturePainter();
icon3dStylePainter.paintBody = function (geoCanvas) {
geoCanvas.drawShape(verticalLine, {
stroke: {
color: '#de2d26',
width: 3
},
occlusionMode: OcclusionMode.VISIBLE_ONLY,
draped: false
});
geoCanvas.drawIcon(imagePoint, {
draped: false,
image: createPinIcon(30, '#de2d26', '1', 'white'),
anchorY: '30px',
occlusionMode: OcclusionMode.ALWAYS_VISIBLE
});
};
const featureLayer = new FeatureLayer(featureModel, { id: name, label: label, painter: icon3dStylePainter, visible: visible });
map.layerTree.addChild(featureLayer);
}
class SearchPanel {
private domElement: HTMLDivElement;
private inputElement: HTMLInputElement;
private inputCleanButton: HTMLSpanElement;
private loaderElement: HTMLDivElement;
private resultsCountElement: HTMLSpanElement;
private resultsElement: HTMLSpanElement;
private requestTime: number;
constructor(private hereSearchService, private showPin: any, private hideLayer: any) {
const rootEle = document.createElement('div');
rootEle.id = 'search-panel';
rootEle.className = 'hide empty';
map.domNode.appendChild(rootEle);
const searchInputPanelEle = document.createElement('div');
searchInputPanelEle.id = 'search-input-panel';
rootEle.appendChild(searchInputPanelEle);
const searchEle = document.createElement('input');
searchEle.id = 'search';
searchEle.type = 'search';
searchEle.autocomplete = 'off';
searchEle.placeholder = 'Address, Place, POI, ..';
searchInputPanelEle.appendChild(searchEle);
const searchClearEle = document.createElement('span');
searchClearEle.id = 'search-clear';
searchClearEle.innerHTML = 'x';
searchInputPanelEle.appendChild(searchClearEle);
const searchResultsDescPanelEle = document.createElement('div');
searchResultsDescPanelEle.id = 'search-results-desc-panel';
rootEle.appendChild(searchResultsDescPanelEle);
const searchResultsDescEle = document.createElement('div');
searchResultsDescEle.id = 'search-results-desc';
searchResultsDescPanelEle.appendChild(searchResultsDescEle);
const searchResultsCountEle = document.createElement('span');
searchResultsCountEle.id = 'search-results-count';
searchResultsCountEle.textContent = '0';
searchResultsCountEle.style.display = 'none';
searchResultsDescEle.appendChild(searchResultsCountEle);
const searchResultsLoaderEle = document.createElement('div');
searchResultsLoaderEle.id = 'search-results-loader';
searchResultsLoaderEle.className = 'preloader-dots dot hide';
searchResultsDescPanelEle.appendChild(searchResultsLoaderEle);
for (let i = 0; i < 5; i++) {
const dotEle = document.createElement('div');
dotEle.className = 'dot';
searchResultsLoaderEle.appendChild(dotEle);
}
const searchResultsEle = document.createElement('div');
searchResultsEle.className = 'search-results';
rootEle.appendChild(searchResultsEle);
this.domElement = rootEle;
this.inputElement = searchEle;
this.inputCleanButton = searchClearEle;
this.loaderElement = searchResultsLoaderEle;
this.resultsCountElement = searchResultsCountEle;
this.resultsElement = searchResultsEle;
this.inputElement.addEventListener('input', () => this.onInput());
this.inputCleanButton.addEventListener('click', () => this.onInputClean());
this.domElement.classList.remove('hide');
}
private async onInput() {
if (this.inputElement.value === '') {
this.domElement.classList.add('empty');
this.resultsCountElement.innerText = '0';
this.loaderElement.classList.add('hide');
this.resultsElement.innerHTML = '';
this.inputCleanButton.click();
return;
}
this.domElement.classList.remove('empty');
this.loaderElement.classList.remove('hide');
this.requestTime = Date.now();
const thatRequestTime = this.requestTime;
const autosuggestItems = await this.performHereQuery(this.inputElement.value);
if (this.requestTime !== thatRequestTime) {
return;
}
this.loaderElement.classList.add('hide');
this.renderResults(autosuggestItems);
}
private renderResults(results: any) {
this.resultsCountElement.innerText = results.length + "";
const fragment = document.createDocumentFragment();
for (const item of results) {
fragment.appendChild(this.createRowElement(item));
}
this.resultsElement.innerHTML = '';
this.resultsElement.appendChild(fragment);
}
private createRowElement(item: any) {
const resultElement = document.createElement('div');
const resultElementHeader = document.createElement('div');
const resultElementSubtitle = document.createElement('div');
resultElementSubtitle.classList.add('search-result-subtitle');
resultElementHeader.classList.add('search-result-header');
resultElement.classList.add('search-result-row');
//resultElement.innerText = item.title;
resultElementHeader.innerText = item.title;
if(item.address?.label) {
resultElementSubtitle.innerText = item.address.label;
}
resultElement.title = `${item.title} \n${item.address?.label ? item.address.label : ''}`;
//resultElement.title = "AXSAXAXAAX" + item.title + "
" + item.address?.label ? item.address.label : '';
resultElement.appendChild(resultElementHeader);
resultElement.appendChild(resultElementSubtitle);
resultElement.addEventListener('click', () => {
const oldSelectedRow = this.domElement.querySelector('.search-result-row.selected');
oldSelectedRow && oldSelectedRow.classList.remove('selected');
resultElement.classList.add('selected');
this.showPin([item.position.lat, item.position.lng], item.mapView, wgs84Ref);
});
return resultElement;
}
private async performHereQuery(searchInput: string) {
let lon, lat;
try {
const viewCenterPoint = window.map.viewToMapTransformation.transform(ShapeFactory.createPoint(null, [window.map.viewSize[0]/2, window.map.viewSize[1]/2]));
const wgs84Point = mapToWgs84Transformation.transform(viewCenterPoint);
lon = wgs84Point.x;
lat = wgs84Point.y;
} catch(e) {
lon = 0;
lat = 0;
}
const response = await this.hereSearchService.autosuggest({
// Search query
q: searchInput,
// Center of the search context
at: `${lat},${lon}`
}, (result) => {
}, console.error);
return response.items;
}
private onInputClean() {
this.inputElement.value = '';
this.hideLayer();
this.onInput();
}
}
function createPinIcon(size, color, text, textColor) {
const canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size * 2;
const ctx = canvas.getContext('2d');
// circle
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 2, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
// text
ctx.fillStyle = textColor;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(text, size / 2, size / 2);
return canvas;
}
function loadExternalLibraries(urls: string[]): Promise {
return Promise.all(urls.map((u) => loadScript(u)));
}
function loadScript(url: string): Promise {
const head = document.getElementsByTagName('head')[0];
const script = document.createElement('script');
script.type = 'text/javascript';
script.charset = 'utf-8';
script.src = url;
const pr = new Promise((resolve, reject) => {
script.onload = resolve;
});
head.appendChild(script);
return pr;
}
function main() {
/*HERE Setup*/
const herePlatform = new H.service.Platform({
'apikey': 'API_KEY_GOES_HERE'
});
const hereSearchService = herePlatform.getSearchService();
/************/
new SearchPanel(hereSearchService,
(coords: number[], fitBounds: any, ref: CoordinateReference) => {
showPointOfInterestLayer('poi', 'POI', true, coords, ref, fitBounds);
},
() => {
removeLayerById('poi');
}
);
}
ready(() => {
loadExternalLibraries([
'https://js.api.here.com/v3/3.1/mapsjs-core.js'
]).then(() => {
loadExternalLibraries([
'https://js.api.here.com/v3/3.1/mapsjs-service.js'
]).then(() => {
main();
});
});
});
Dashboard JS
import { Bounds } from '@luciad/ria/shape/Bounds';
import { CoordinateReference } from '@luciad/ria/reference/CoordinateReference';
import * as ReferenceProvider from '@luciad/ria/reference/ReferenceProvider';
import * as TransformationFactory from '@luciad/ria/transformation/TransformationFactory';
import { Feature } from '@luciad/ria/model/feature/Feature';
import { FeatureModel } from '@luciad/ria/model/feature/FeatureModel';
import { MemoryStore } from '@luciad/ria/model/store/MemoryStore';
import * as ShapeFactory from '@luciad/ria/shape/ShapeFactory';
import { BasicFeaturePainter } from '@luciad/ria/view/feature/BasicFeaturePainter';
import { FeatureLayer } from '@luciad/ria/view/feature/FeatureLayer';
import { OcclusionMode } from '@luciad/ria/view/style/OcclusionMode';
const map = this.getStageModel().mapViews[0].getMap().map;
const poiLayerId = "poi";
const poiLayerLabel ="Poi";
const wgs84Ref = ReferenceProvider.getReference('EPSG:4326');
const mapToWgs84Transformation = TransformationFactory.createTransformation(map.reference, wgs84Ref);
const MAX_RESULTS = 10;
function showPointOfInterestLayer(name: string, label: string, visible: boolean, coords: number[], ref: CoordinateReference, fitBounds: any) {
const oldLayer = map.layerTree.findLayerById(name);
oldLayer && map.layerTree.removeChild(oldLayer);
const location = ShapeFactory.createPoint(ref, [coords[1], coords[0]]);
location.z = 0;
let wgs84Bounds: Bounds;
//If HERE sends boundingbox, use it. Else create 1km GeoBuffer around point as bounding box to fit to.
if(fitBounds && fitBounds.west) {
wgs84Bounds = ShapeFactory.createBounds(wgs84Ref, [fitBounds.west, fitBounds.east - fitBounds.west, fitBounds.south, fitBounds.north - fitBounds.south]);
} else {
const geoBuffer = ShapeFactory.createGeoBuffer(wgs84Ref, ShapeFactory.createPolyline(wgs84Ref, [location]), 1000);
wgs84Bounds = geoBuffer.bounds;
}
map.mapNavigator.fit({
bounds: wgs84Bounds,
animate: false
});
const pHeight = ShapeFactory.createPoint(ref, [location.x, location.y, location.z + 50]);
const verticalLine = ShapeFactory.createPolyline(ref, [location, pHeight]);
const imagePoint = ShapeFactory.createPoint(ref, [location.x, location.y, location.z + 50]);
const feature = new Feature(location, {}, 1);
const store = new MemoryStore({
data: [feature]
});
const featureModel = new FeatureModel(store, { reference: ref });
const icon3dStylePainter = new BasicFeaturePainter();
icon3dStylePainter.paintBody = function (geoCanvas) {
geoCanvas.drawShape(verticalLine, {
stroke: {
color: '#de2d26',
width: 3
},
occlusionMode: OcclusionMode.VISIBLE_ONLY,
draped: false
});
geoCanvas.drawIcon(imagePoint, {
draped: false,
image: createPinIcon(30, '#de2d26', '1', 'white'),
anchorY: '30px',
occlusionMode: OcclusionMode.ALWAYS_VISIBLE
});
};
const featureLayer = new FeatureLayer(featureModel, { id: name, label: label, painter: icon3dStylePainter, visible: visible });
map.layerTree.addChild(featureLayer);
}
class SearchPanel {
private domElement: HTMLDivElement;
private inputElement: HTMLInputElement;
private inputCleanButton: HTMLSpanElement;
private loaderElement: HTMLDivElement;
private resultsCountElement: HTMLSpanElement;
private resultsElement: HTMLSpanElement;
private requestTime: number;
constructor(private hereSearchService, private showPin: any, private hideLayer: any) {
const rootEle = document.createElement('div');
rootEle.id = 'search-panel';
rootEle.className = 'hide empty';
map.domNode.appendChild(rootEle);
const searchInputPanelEle = document.createElement('div');
searchInputPanelEle.id = 'search-input-panel';
rootEle.appendChild(searchInputPanelEle);
const searchEle = document.createElement('input');
searchEle.id = 'search';
searchEle.type = 'search';
searchEle.autocomplete = 'off';
searchEle.placeholder = 'Address, Place, POI, ..';
searchInputPanelEle.appendChild(searchEle);
const searchClearEle = document.createElement('span');
searchClearEle.id = 'search-clear';
searchClearEle.innerHTML = 'x';
searchInputPanelEle.appendChild(searchClearEle);
const searchResultsDescPanelEle = document.createElement('div');
searchResultsDescPanelEle.id = 'search-results-desc-panel';
rootEle.appendChild(searchResultsDescPanelEle);
const searchResultsDescEle = document.createElement('div');
searchResultsDescEle.id = 'search-results-desc';
searchResultsDescPanelEle.appendChild(searchResultsDescEle);
const searchResultsCountEle = document.createElement('span');
searchResultsCountEle.id = 'search-results-count';
searchResultsCountEle.textContent = '0';
searchResultsCountEle.style.display = 'none';
searchResultsDescEle.appendChild(searchResultsCountEle);
const searchResultsLoaderEle = document.createElement('div');
searchResultsLoaderEle.id = 'search-results-loader';
searchResultsLoaderEle.className = 'preloader-dots dot hide';
searchResultsDescPanelEle.appendChild(searchResultsLoaderEle);
for (let i = 0; i < 5; i++) {
const dotEle = document.createElement('div');
dotEle.className = 'dot';
searchResultsLoaderEle.appendChild(dotEle);
}
const searchResultsEle = document.createElement('div');
searchResultsEle.className = 'search-results';
rootEle.appendChild(searchResultsEle);
this.domElement = rootEle;
this.inputElement = searchEle;
this.inputCleanButton = searchClearEle;
this.loaderElement = searchResultsLoaderEle;
this.resultsCountElement = searchResultsCountEle;
this.resultsElement = searchResultsEle;
this.inputElement.addEventListener('input', () => this.onInput());
this.inputCleanButton.addEventListener('click', () => this.onInputClean());
this.domElement.classList.remove('hide');
console.log("init done", this);
}
private async onInput() {
if (this.inputElement.value === '') {
this.domElement.classList.add('empty');
this.resultsCountElement.innerText = '0';
this.loaderElement.classList.add('hide');
this.resultsElement.innerHTML = '';
this.inputCleanButton.click();
return;
}
this.domElement.classList.remove('empty');
this.loaderElement.classList.remove('hide');
this.requestTime = Date.now();
const thatRequestTime = this.requestTime;
const autosuggestItems = await this.performHereQuery(this.inputElement.value);
if (this.requestTime !== thatRequestTime) {
return;
}
this.loaderElement.classList.add('hide');
this.renderResults(autosuggestItems);
}
private renderResults(results: any) {
this.resultsCountElement.innerText = results.length + "";
const fragment = document.createDocumentFragment();
for (const item of results) {
fragment.appendChild(this.createRowElement(item));
}
this.resultsElement.innerHTML = '';
this.resultsElement.appendChild(fragment);
}
private createRowElement(item: any) {
const resultElement = document.createElement('div');
const resultElementHeader = document.createElement('div');
const resultElementSubtitle = document.createElement('div');
resultElementSubtitle.classList.add('search-result-subtitle');
resultElementHeader.classList.add('search-result-header');
resultElement.classList.add('search-result-row');
//resultElement.innerText = item.title;
resultElementHeader.innerText = item.title;
if(item.address?.label) {
resultElementSubtitle.innerText = item.address.label;
}
resultElement.title = `${item.title} \n${item.address?.label ? item.address.label : ''}`;
//resultElement.title = "AXSAXAXAAX" + item.title + "
" + item.address?.label ? item.address.label : ";
resultElement.appendChild(resultElementHeader);
resultElement.appendChild(resultElementSubtitle);
resultElement.addEventListener('click', () => {
const oldSelectedRow = this.domElement.querySelector('.search-result-row.selected');
oldSelectedRow && oldSelectedRow.classList.remove('selected');
resultElement.classList.add('selected');
this.showPin([item.position.lat, item.position.lng], item.mapView, wgs84Ref);
});
return resultElement;
}
private async performHereQuery(searchInput: string) {
let lon, lat;
try {
const viewCenterPoint = window.map.viewToMapTransformation.transform(ShapeFactory.createPoint(null, [window.map.viewSize[0]/2, window.map.viewSize[1]/2]));
const wgs84Point = mapToWgs84Transformation.transform(viewCenterPoint);
lon = wgs84Point.x;
lat = wgs84Point.y;
} catch(e) {
lon = 0;
lat = 0;
}
const response = await this.hereSearchService.autosuggest({
// Search query
q: searchInput,
// Center of the search context
at: `${lat},${lon}`
}, (result) => {
}, console.error);
return response.items;
}
private onInputClean() {
this.inputElement.value = '';
this.hideLayer();
this.onInput();
}
}
function createPinIcon(size, color, text, textColor) {
const canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size * 2;
const ctx = canvas.getContext('2d');
// circle
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 2, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
// text
ctx.fillStyle = textColor;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(text, size / 2, size / 2);
return canvas;
}
function loadExternalLibraries(urls: string[]): Promise {
return Promise.all(urls.map((u) => loadScript(u)));
}
function loadScript(url: string): Promise {
const head = document.getElementsByTagName('head')[0];
const script = document.createElement('script');
script.type = 'text/javascript';
script.charset = 'utf-8';
script.src = url;
const pr = new Promise((resolve, reject) => {
script.onload = resolve;
});
head.appendChild(script);
return pr;
}
function main() {
/*HERE Setup*/
const herePlatform = new H.service.Platform({
'apikey': 'APIKEY_GOES_HERE'
});
const hereSearchService = herePlatform.getSearchService();
/************/
new SearchPanel(hereSearchService,
(coords: number[], fitBounds: any, ref: CoordinateReference) => {
showPointOfInterestLayer(poiLayerId, poiLayerLabel, true, coords, ref, fitBounds);
},
() => {
const oldLayer = map.layerTree.findLayerById(poiLayerId);
oldLayer && map.layerTree.removeChild(oldLayer);
}
);
}
loadExternalLibraries([
'https://js.api.here.com/v3/3.1/mapsjs-core.js'
]).then(() => {
loadExternalLibraries([
'https://js.api.here.com/v3/3.1/mapsjs-service.js'
]).then(() => {
main();
});
});
Custom Style
Browser CSS
clears the ‘X’ from Internet Explorer */
input[type=search]::-ms-clear { display: none; width : 0; height: 0; }
input[type=search]::-ms-reveal { display: none; width : 0; height: 0; }
/* clears the ‘X’ from Chrome */
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-results-button,
input[type="search"]::-webkit-search-results-decoration { display: none; }
div#search-panel {
position: absolute;
top: 20px;
left: 80px;
background-color: #222;
opacity: 0.85;
color: #Fff;
width: 320px;
padding: 5px;
font-size: 14px;
}
input#search {
width: 100%;
height: 32px;
left: 100px;
background-color: #222;
opacity: 0.85;
color: white;
border: 0;
border-bottom: 1px solid white;
outline: none;
}
div#search-results {
left: 100px;
background-color: #222;
opacity: 0.85;
color: #Fff;
width: 100%;
max-height: 600px;
overflow-y: auto;
}
div#search-results > div {
padding: 5px;
}
.search-result-subtitle {
opacity: 0.5;
font-size: 0.7em;
overflow: hidden;
text-overflow: ellipsis;
}
.search-result-header {
overflow: hidden;
text-overflow: ellipsis;
}
.search-result-row {
cursor: pointer;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.search-result-row:hover {
background-color: #2b3540;
}
.search-result-row.selected {
background-color: #fff!important;
color: black;
}
#search-results-desc {
float: left;
margin-right: 10px;
}
#search-results-desc-panel {
overflow: hidden;
margin: 10px 0;
}
#search-clear {
position: absolute;
right: 2px;
bottom: 8px;
cursor: pointer;
}
.empty #search-clear {
display: none;
}
.empty #search-results-desc-panel {
display: none;
}
#search-input-panel {
position: relative;
}
.activateButton {
font-size: 1.5rem;
padding: 8px;
width: fit-content;
cursor: pointer;
margin-left: 8px;
}
.activateButton.active {
color: rgb(0, 150, 184);
}
Dashboard CSS
clears the ‘X’ from Internet Explorer */
input[type=search]::-ms-clear { display: none; width : 0; height: 0; }
input[type=search]::-ms-reveal { display: none; width : 0; height: 0; }
/* clears the ‘X’ from Chrome */
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-results-button,
input[type="search"]::-webkit-search-results-decoration { display: none; }
div#search-panel {
position: absolute;
top: 50px; /* 20px without header */
left: 80px;
background-color: #222;
opacity: 0.85;
color: #Fff;
width: 320px;
padding: 5px;
font-size: 14px;
}
input#search {
width: 100%;
height: 32px;
left: 100px;
background-color: #222;
opacity: 0.85;
color: white;
border: 0;
border-bottom: 1px solid white;
outline: none;
}
div#search-results {
left: 100px;
background-color: #222;
opacity: 0.85;
color: #Fff;
width: 100%;
max-height: 600px;
overflow-y: auto;
}
div#search-results > div {
padding: 5px;
}
.search-result-subtitle {
opacity: 0.5;
font-size: 0.7em;
overflow: hidden;
text-overflow: ellipsis;
}
.search-result-header {
overflow: hidden;
text-overflow: ellipsis;
}
.search-result-row {
cursor: pointer;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.search-result-row:hover {
background-color: #2b3540;
}
.search-result-row.selected {
background-color: #fff!important;
color: black;
}
#search-results-desc {
float: left;
margin-right: 10px;
}
#search-results-desc-panel {
overflow: hidden;
margin: 10px 0;
}
#search-clear {
position: absolute;
right: 2px;
bottom: 8px;
cursor: pointer;
}
.empty #search-clear {
display: none;
}
.empty #search-results-desc-panel {
display: none;
}
#search-input-panel {
position: relative;
}
.activateButton {
font-size: 1.5rem;
padding: 8px;
width: fit-content;
cursor: pointer;
margin-left: 8px;
}
.activateButton.active {
color: rgb(0, 150, 184);
}