Skip to content

Commit 6b76d86

Browse files
committed
replace root page search with quick search popup
1 parent 0447982 commit 6b76d86

3 files changed

Lines changed: 23 additions & 123 deletions

File tree

src/routes/(info)/lttstore/+layout.svelte

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import ProductSearchModal from "./ProductSearchModal.svelte";
88
import {popup} from "$lib/replacements/popup.ts";
99
import type { MouseEventHandler } from "svelte/elements";
10+
import { setContext } from "svelte";
1011
1112
let { data, children } = $props();
1213
@@ -24,6 +25,8 @@
2425
2526
let searchOpen = $state(false);
2627
28+
setContext("lttstore-search-modal", () => searchOpen = true)
29+
2730
function keypress(event: KeyboardEvent) {
2831
if(event.key === "P" && document.activeElement?.tagName !== "INPUT") {
2932
searchOpen = true;

src/routes/(info)/lttstore/+page.svelte

Lines changed: 6 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
44
import LTTProductCard from "$lib/lttstore/LTTProductCard.svelte";
55
import { page } from "$app/state";
6-
import { onMount } from "svelte";
6+
import { getContext, onMount } from "svelte";
77
import {flip} from "svelte/animate";
88
import {slide, fade} from "svelte/transition";
99
import { Progress } from "@skeletonlabs/skeleton-svelte";
@@ -17,58 +17,7 @@
1717
1818
let { data } = $props();
1919
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-
3120
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-
}
7221
7322
let loading = $state(false);
7423
async function reload() {
@@ -81,16 +30,8 @@
8130
onMount(() => {
8231
setTimeout(() => mounted = true, 0)
8332
});
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");
9435
</script>
9536
<svelte:head>
9637
<title>LTTStore Watcher - Whenplane</title>
@@ -121,68 +62,11 @@
12162
<br>
12263
<br>
12364

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>
13568
<a href="/lttstore/advanced-search">Advanced Search</a>
13669
<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}
18670
<br>
18771

18872

src/routes/(info)/lttstore/ProductSearchModal.svelte

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import CircleProgress from "$lib/replacements/CircleProgress.svelte";
1212
import type { MouseEventHandler } from "svelte/elements";
1313
import { sha256 } from "$lib/utils.ts";
14+
import { onMount } from "svelte";
1415
1516
const searchClient = new SearchClient({
1617
'nodes': [{
@@ -87,10 +88,22 @@
8788
$effect(() => {
8889
search(searchText);
8990
});
91+
92+
let input = $state<HTMLInputElement>();
93+
onMount(() => {
94+
input?.focus()
95+
})
9096
</script>
9197

9298
<div class="s-container p-4 absolute">
93-
<input class="input block px-2 pl-4 py-0.5 bg-surface-800/85 rounded-2xl border border-surface-500" autofocus placeholder="Find a product" bind:value={searchText} onkeydown={keyPress}>
99+
<input
100+
class="input block px-2 pl-4 py-0.5 bg-surface-800/85 rounded-2xl border border-surface-500"
101+
autofocus
102+
placeholder="Find a product"
103+
bind:value={searchText}
104+
onkeydown={keyPress}
105+
bind:this={input}
106+
>
94107
<div class="inline-block absolute top-4 right-8">
95108
{#if waiting}
96109
<CircleProgress class="inline-block" width="w-6"/>

0 commit comments

Comments
 (0)