|
4 | 4 |
|
5 | 5 | <script lang="ts"> |
6 | 6 | import { Search } from 'js-search' |
| 7 | + import { page } from '$app/stores' |
7 | 8 |
|
8 | 9 | import FileCode from '@nick-mazuk/ui-svelte/src/elements/marketing-icon/file-code.svelte' |
9 | 10 | import EmptyState from '@nick-mazuk/ui-svelte/src/components/empty-state/empty-state.svelte' |
|
23 | 24 | search.addIndex(['author', 'name']) |
24 | 25 | search.addIndex('categories') |
25 | 26 |
|
26 | | - const allNames = new Set<string>() |
| 27 | + const allIndexes = new Set<number>() |
27 | 28 |
|
28 | 29 | const normalizeName = (name: string) => name.normalize('NFD').replace(/[\u0300-\u036f]/g, '') |
29 | | - scripts.forEach((script) => { |
| 30 | + scripts.forEach((script, index) => { |
30 | 31 | search.addDocument({ |
31 | 32 | ...script, |
32 | 33 | name: normalizeName(script.name), |
| 34 | + index, |
33 | 35 | }) |
34 | | - allNames.add(normalizeName(script.name)) |
| 36 | + allIndexes.add(index) |
35 | 37 | }) |
36 | 38 |
|
37 | | - let searchValue = '' |
| 39 | + let searchValue = $page.query.get('search') ?? '' |
38 | 40 |
|
39 | 41 | const handleSearchChange = (event: TextInputChangeEvent) => |
40 | 42 | (searchValue = event.detail.parsedValue) |
41 | 43 |
|
42 | | - type DisplayedDocuments = { items: Set<string>; first: string; last: string } |
| 44 | + type DisplayedDocuments = { items: Set<number>; first: number; last: number } |
43 | 45 | const searchCache: { |
44 | 46 | [key: string]: DisplayedDocuments |
45 | 47 | } = { |
46 | 48 | '': { |
47 | | - items: allNames, |
48 | | - first: normalizeName(scripts[0].name), |
49 | | - last: normalizeName(scripts[scripts.length - 1].name), |
| 49 | + items: allIndexes, |
| 50 | + first: 0, |
| 51 | + last: scripts.length - 1, |
50 | 52 | }, |
51 | 53 | } |
52 | 54 |
|
|
58 | 60 | const results: ScriptData[] = search.search(searchValue) |
59 | 61 | const sortedResults = results.sort((a, b) => a.name.localeCompare(b.name)) |
60 | 62 | displayedDocuments = { |
61 | | - items: new Set(results.map((script: ScriptData) => script.name)), |
62 | | - first: normalizeName(sortedResults[0]?.name ?? ''), |
63 | | - last: normalizeName(sortedResults[results.length - 1]?.name ?? ''), |
| 63 | + items: new Set(results.map((script: ScriptData) => script.index)), |
| 64 | + first: sortedResults[0]?.index ?? -1, |
| 65 | + last: sortedResults[sortedResults.length - 1]?.index ?? -1, |
64 | 66 | } |
65 | 67 | } |
66 | 68 | } |
| 69 | + $: if (typeof window !== 'undefined') |
| 70 | + window.history.replaceState(null, '', searchValue ? `?search=${searchValue}` : '.') |
67 | 71 | </script> |
68 | 72 |
|
69 | 73 | <main class="wrapper my-6" id="main-content"> |
|
78 | 82 | <SearchInput |
79 | 83 | on:change="{handleSearchChange}" |
80 | 84 | placeholder="Search…" |
| 85 | + defaultValue="{searchValue}" |
81 | 86 | helpText="Found {formatNumber(displayedDocuments.items.size)} script{displayedDocuments |
82 | 87 | .items.size === 1 |
83 | 88 | ? '' |
84 | 89 | : 's'}" |
85 | 90 | /> |
86 | 91 | <Spacer /> |
87 | 92 | <Container> |
88 | | - {#each scripts as item} |
| 93 | + {#each scripts as item, index} |
89 | 94 | <Script |
90 | 95 | data="{item}" |
91 | | - show="{displayedDocuments.items.has(normalizeName(item.name))}" |
92 | | - first="{normalizeName(item.name) === displayedDocuments.first}" |
93 | | - last="{normalizeName(item.name) === displayedDocuments.last}" |
| 96 | + show="{displayedDocuments.items.has(index)}" |
| 97 | + first="{index === displayedDocuments.first}" |
| 98 | + last="{index === displayedDocuments.last}" |
94 | 99 | /> |
95 | 100 | {/each} |
96 | 101 | {#if displayedDocuments.items.size === 0} |
|
99 | 104 | description="There are no scripts that match your search" |
100 | 105 | > |
101 | 106 | <svelte:fragment slot="image"> |
102 | | - <FileCode class="w-40" /> |
| 107 | + <FileCode class="w-32" /> |
103 | 108 | </svelte:fragment> |
104 | 109 | </EmptyState> |
105 | 110 | {/if} |
|
0 commit comments