|
3 | 3 |
|
4 | 4 | import LTTProductCard from "$lib/lttstore/LTTProductCard.svelte"; |
5 | 5 | import { page } from "$app/state"; |
6 | | - import { onMount } from "svelte"; |
| 6 | + import { getContext, onMount } from "svelte"; |
7 | 7 | import {flip} from "svelte/animate"; |
8 | 8 | import {slide, fade} from "svelte/transition"; |
9 | 9 | import { Progress } from "@skeletonlabs/skeleton-svelte"; |
|
17 | 17 |
|
18 | 18 | let { data } = $props(); |
19 | 19 |
|
20 | | - const searchClient = new SearchClient({ |
21 | | - 'nodes': [{ |
22 | | - 'host': 'search.ajg0702.us', |
23 | | - 'port': 443, |
24 | | - 'protocol': 'https' |
25 | | - }], |
26 | | - // this api key only has access to search, don't worry |
27 | | - 'apiKey': "swyHTJhzz7MQIxDjBqE2dpOCM6DIU10P", |
28 | | - 'connectionTimeoutSeconds': 10 |
29 | | - }); |
30 | | -
|
31 | 20 | let waiting = $state(false); |
32 | | - let searchPromise: Promise<SearchResponse<ProductSearchIndex> | undefined> | undefined = $state(); |
33 | | - let searchResults: SearchResponse<ProductSearchIndex> | undefined = $state(); |
34 | | - let networkError = $state(false); |
35 | | -
|
36 | | - let searchText = $state(""); |
37 | | -
|
38 | | - const resultsPerPage = 100; |
39 | | -
|
40 | | - function search(text: string, page?: number) { |
41 | | - if(!text) { |
42 | | - searchPromise = undefined; |
43 | | - searchResults = undefined; |
44 | | - return; |
45 | | - } |
46 | | - searchPromise = searchClient.collections<ProductSearchIndex>("lttstore_products").documents() |
47 | | - .search({ |
48 | | - q: text, |
49 | | - query_by: "title,handle,description", |
50 | | - query_by_weights: "4,2,0", |
51 | | - text_match_type: "max_weight", |
52 | | - page: page ?? 1, |
53 | | - per_page: resultsPerPage |
54 | | - }, {cacheSearchResultsForSeconds: 60}) |
55 | | - .then(r => { |
56 | | - if(r.request_params.q === searchText) { |
57 | | - searchResults = r as SearchResponse<ProductSearchIndex> |
58 | | - } |
59 | | - return r as SearchResponse<ProductSearchIndex>; |
60 | | - }) |
61 | | - .then(r => { |
62 | | - networkError = false; |
63 | | - return r; |
64 | | - }) |
65 | | - .catch(e => { |
66 | | - console.error("Error while searching:", e); |
67 | | - searchResults = undefined; |
68 | | - networkError = true; |
69 | | - return undefined; |
70 | | - }) |
71 | | - } |
72 | 21 |
|
73 | 22 | let loading = $state(false); |
74 | 23 | async function reload() { |
|
81 | 30 | onMount(() => { |
82 | 31 | setTimeout(() => mounted = true, 0) |
83 | 32 | }); |
84 | | - run(() => { |
85 | | - let tmpText = searchText+""; |
86 | | - waiting = true; |
87 | | - setTimeout(() => { |
88 | | - if(searchText === tmpText) { |
89 | | - waiting = false; |
90 | | - search(searchText); |
91 | | - } |
92 | | - }, 100) |
93 | | - }); |
| 33 | +
|
| 34 | + const openSearch = getContext<() => void>("lttstore-search-modal"); |
94 | 35 | </script> |
95 | 36 | <svelte:head> |
96 | 37 | <title>LTTStore Watcher - Whenplane</title> |
|
121 | 62 | <br> |
122 | 63 | <br> |
123 | 64 |
|
124 | | - <input placeholder="Search for products" bind:value={searchText} class="input w-64 p-2 pl-4"> |
125 | | - <div class="inline-block w-12"> |
126 | | - {#await searchPromise} |
127 | | - {#if !waiting} |
128 | | - <Progress class="inline-block" width="w-6" stroke={250}/> |
129 | | - {/if} |
130 | | - {/await} |
131 | | - {#if waiting} |
132 | | - <Progress class="inline-block" width="w-6" stroke={250}/> |
133 | | - {/if} |
134 | | - </div> |
| 65 | + <button class="input w-64 p-1 mx-2 pl-4 text-left inline-block bg-surface-900 text-white/40" onclick={() => openSearch()}> |
| 66 | + Search for products |
| 67 | + </button> |
135 | 68 | <a href="/lttstore/advanced-search">Advanced Search</a> |
136 | 69 | <br> |
137 | | - {#if searchResults && searchResults.hits} |
138 | | - {#each searchResults.hits as result (result.document.id)} |
139 | | - {@const productData = JSON.parse(result.document.product)} |
140 | | - {@const descriptionSnippet = result.highlight?.description?.snippet?.replaceAll("</p>", "\n")} |
141 | | - {@const openingIndex = descriptionSnippet?.indexOf("<")} |
142 | | - {@const closingIndex = descriptionSnippet?.indexOf(">")} |
143 | | - <a class="block card p-2 m-1 truncate" href="/lttstore/products/{result.document.handle}" animate:flip={{ duration: 50 }} transition:slide> |
144 | | - <img src={productData.featured_image ?? productData.images[0]} class="inline-block h-8 w-8 rounded-md"> |
145 | | - <span class="result-highlight" class:line-through={!(result.document.available ?? true)}> |
146 | | - {@html sanitizeHtml(result.highlight?.title?.snippet ?? result.document.title, {allowedTags: ["mark"]})} |
147 | | - </span> |
148 | | - |
149 | | - <span class="opacity-70 max-w-full truncate result-highlight"> |
150 | | - <!--{descriptionSnippet}--> |
151 | | - {@html |
152 | | - sanitizeHtml( |
153 | | - descriptionSnippet |
154 | | - ?.substring( // we trim this so that if typesense starts the snippet in the middle of a html tag, we can remove that |
155 | | - closingIndex && openingIndex && |
156 | | - closingIndex >= 0 && |
157 | | - ( |
158 | | - openingIndex >= 0 ? openingIndex > closingIndex : true |
159 | | - ) |
160 | | - ? |
161 | | - closingIndex+1 : |
162 | | - 0 |
163 | | - ) ?? |
164 | | - productData.description, |
165 | | - {allowedTags: ["mark"]} |
166 | | - )} |
167 | | - </span> |
168 | | - <br> |
169 | | - </a> |
170 | | - {:else} |
171 | | - No results found. |
172 | | - {/each} |
173 | | - {#if searchResults.hits.length === resultsPerPage} |
174 | | - {searchResults.found - resultsPerPage} more results hidden. Please narrow your search query.<br> |
175 | | - {/if} |
176 | | - {/if} |
177 | | - {#if networkError} |
178 | | - <span class="text-error-500"> |
179 | | - <br> |
180 | | - A network error occurred while trying to get the results for your search.<br> |
181 | | - Check your internet connection.<br> |
182 | | - If your network connection is fine, the search server might be down. |
183 | | - Try again in a few minutes, and <a href="/support">contact me</a> if it is still down. |
184 | | - </span> |
185 | | - {/if} |
186 | 70 | <br> |
187 | 71 |
|
188 | 72 |
|
|
0 commit comments