]> git.openstreetmap.org Git - nominatim-ui.git/blob - src/components/ResultsList.svelte
Merge remote-tracking branch 'upstream/master'
[nominatim-ui.git] / src / components / ResultsList.svelte
1 <script>
2   import { formatLabel } from '../lib/helpers.js';
3   import { SvelteURLSearchParams } from 'svelte/reactivity';
4
5   import DetailsLink from './DetailsLink.svelte';
6   import Welcome from './Welcome.svelte';
7   import MapIcon from './MapIcon.svelte';
8
9   let { results, reverse_search = false, current_result = $bindable() } = $props();
10
11   let iHighlightNum = $state();
12
13   let sMoreURL = $derived.by(() => {
14     const search_params = new URLSearchParams(window.location.search);
15     const aResults = results;
16     // lonvia wrote: https://github.com/osm-search/nominatim-ui/issues/24
17     // I would suggest to remove the guessing and always show the link. Nominatim only returns
18     // one or two results when it believes the result to be a good enough match.
19     // if (aResults.length >= 10) {
20     let aExcludePlaceIds = [];
21     if (search_params.has('exclude_place_ids')) {
22       aExcludePlaceIds = search_params.get('exclude_place_ids').split(',');
23     }
24     for (var i = 0; i < aResults.length; i += 1) {
25       aExcludePlaceIds.push(aResults[i].place_id);
26     }
27     var parsed_url = new SvelteURLSearchParams(window.location.search);
28     parsed_url.set('exclude_place_ids', aExcludePlaceIds.join(','));
29     return '?' + parsed_url.toString();
30   });
31
32   function handleClick(e) {
33     e.stopPropagation();
34     let result_el = e.target;
35     if (!result_el.className.match('result')) {
36       result_el = result_el.parentElement;
37     }
38     let pos = Number(result_el.dataset.position);
39
40     iHighlightNum = pos;
41   }
42
43   $effect(() => {
44     if (results) {
45       iHighlightNum = 0;
46     }
47   });
48
49   $effect(() => {
50     current_result = (results && results.length > iHighlightNum) ? results[iHighlightNum] : null;
51   });
52
53 </script>
54
55 {#if results && results.length > 0}
56   <div id="searchresults" role="list">
57
58     {#each results as aResult, iResNum}
59       <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
60       <div class="result"
61            class:highlight={iResNum === iHighlightNum}
62            role="listitem"
63            data-position="{iResNum}"
64            onclick={handleClick}
65            onkeypress={handleClick}>
66         <div style="float:right">
67           <MapIcon aPlace={aResult} />
68         </div>
69         <span class="name">{aResult.display_name}</span>
70         <span class="type">{formatLabel(aResult)}</span>
71         <p class="coords">{aResult.lat},{aResult.lon}</p>
72
73         <DetailsLink extra_classes="btn btn-outline-secondary btn-sm" feature={aResult} />
74       </div>
75     {/each}
76
77     {#if sMoreURL && !reverse_search}
78       <div class="more">
79         <a class="btn btn-primary" href="{sMoreURL}">
80           Search for more results
81         </a>
82       </div>
83     {/if}
84   </div>
85 {:else if results}
86   {#if reverse_search}
87     <div id="intro" class="sidebar">Search for coordinates or click anywhere on the map.</div>
88   {:else}
89     <div class="noresults">No search results found</div>
90   {/if}
91 {:else}
92   <Welcome/>
93 {/if}
94
95 <style>
96   .result {
97     font-size: 0.8em;
98     margin: 5px;
99     margin-top: 0;
100     padding: 4px 8px;
101     border-radius: 2px;
102     background: var(--bs-secondary-bg);
103     border: 1px solid var(--bs-secondary-color);
104     cursor: pointer;
105     min-height: 5em;
106   }
107
108   .result.highlight {
109     background-color: var(--bs-primary-bg-subtle);
110     border-color: var(--bs-primary-color-subtle);
111   }
112   .result.highlight :global(a) {
113     margin: 10px auto;
114     display: block;
115     max-width: 10em;
116     padding: 1px;
117     color: var(--bs-secondary-color);
118     background-color: var(--bs-secondary-bg);
119   }
120   .result .type {
121     color: var(--bs-secondary-color);
122     font-size: 0.8em;
123   }
124   .result :global(a) {
125     display: none;
126   }
127
128   .result .coords {
129     display: none;
130   }
131
132   .noresults{
133     text-align: center;
134     padding: 1em;
135   }
136
137   .more{
138     text-align:center;
139     margin-top: 1em;
140   }
141
142   .result.highlight :global(a):hover {
143     background-color: var(--bs-primary-bg-subtle);
144   }
145 </style>