feat(search): load on scroll

This commit is contained in:
Maciej Jur 2023-12-22 23:39:29 +01:00
parent 4c27201c39
commit 51c1ddea0b
Signed by: kamov
GPG key ID: 191CBFF5F72ECAFD
3 changed files with 79 additions and 58 deletions

View file

@ -11,11 +11,11 @@
"astro": "astro"
},
"dependencies": {
"@astrojs/mdx": "^2.0.1",
"@astrojs/svelte": "^5.0.1",
"@astrojs/mdx": "^2.0.2",
"@astrojs/svelte": "^5.0.2",
"@citation-js/plugin-bibtex": "^0.7.2",
"@js-temporal/polyfill": "^0.4.4",
"astro": "^4.0.6",
"astro": "^4.0.7",
"astro-pagefind": "^1.3.0",
"chart.js": "^4.4.1",
"citation-js": "^0.7.4",
@ -32,7 +32,7 @@
"remark-math": "^6.0.0",
"remark-parse": "^11.0.0",
"remark-rehype": "^11.0.0",
"reveal.js": "^5.0.3",
"reveal.js": "^5.0.4",
"svelte": "5.0.0-next.26",
"unified": "^11.0.4",
"unist-util-visit": "^5.0.0"

View file

@ -6,11 +6,11 @@ settings:
dependencies:
'@astrojs/mdx':
specifier: ^2.0.1
version: 2.0.1(astro@4.0.6)
specifier: ^2.0.2
version: 2.0.2(astro@4.0.7)
'@astrojs/svelte':
specifier: ^5.0.1
version: 5.0.1(astro@4.0.6)(svelte@5.0.0-next.26)(typescript@5.3.3)(vite@5.0.10)
specifier: ^5.0.2
version: 5.0.2(astro@4.0.7)(svelte@5.0.0-next.26)(typescript@5.3.3)(vite@5.0.10)
'@citation-js/plugin-bibtex':
specifier: ^0.7.2
version: 0.7.2(@citation-js/core@0.7.1)
@ -18,11 +18,11 @@ dependencies:
specifier: ^0.4.4
version: 0.4.4
astro:
specifier: ^4.0.6
version: 4.0.6(sass@1.69.5)(typescript@5.3.3)
specifier: ^4.0.7
version: 4.0.7(sass@1.69.5)(typescript@5.3.3)
astro-pagefind:
specifier: ^1.3.0
version: 1.3.0(astro@4.0.6)
version: 1.3.0(astro@4.0.7)
chart.js:
specifier: ^4.4.1
version: 4.4.1
@ -69,8 +69,8 @@ dependencies:
specifier: ^11.0.0
version: 11.0.0
reveal.js:
specifier: ^5.0.3
version: 5.0.3
specifier: ^5.0.4
version: 5.0.4
svelte:
specifier: 5.0.0-next.26
version: 5.0.0-next.26
@ -143,8 +143,8 @@ packages:
- supports-color
dev: false
/@astrojs/mdx@2.0.1(astro@4.0.6):
resolution: {integrity: sha512-lWbiNoVV/6DO8hAf6eZmcN28hY/herif9eglw2PXZ5lEPoRu175BvBtuNTt9rH9YA/Ldm5mkNXhvMWNEnMqJkw==}
/@astrojs/mdx@2.0.2(astro@4.0.7):
resolution: {integrity: sha512-pTkUb0+aiVU8MZU6XQKA/FyXdNOKxHwq+3uCIuzWyqjZyRB9hN3G3iokmkXFJhwgxl6gilkYeAKmmciVwnpq6w==}
engines: {node: '>=18.14.1'}
peerDependencies:
astro: ^4.0.0
@ -152,7 +152,7 @@ packages:
'@astrojs/markdown-remark': 4.0.1
'@mdx-js/mdx': 3.0.0
acorn: 8.11.2
astro: 4.0.6(sass@1.69.5)(typescript@5.3.3)
astro: 4.0.7(sass@1.69.5)(typescript@5.3.3)
es-module-lexer: 1.4.1
estree-util-visit: 2.0.0
github-slugger: 2.0.0
@ -176,15 +176,15 @@ packages:
prismjs: 1.29.0
dev: false
/@astrojs/svelte@5.0.1(astro@4.0.6)(svelte@5.0.0-next.26)(typescript@5.3.3)(vite@5.0.10):
resolution: {integrity: sha512-MQvm0VmkiHVBb41hkKvQKtZa2YZqImdJD23dDW6EGhFxRy1GEgJ4Hm6p4T30FXrLPQUoiay/BU5U/lHDd6ZlNg==}
/@astrojs/svelte@5.0.2(astro@4.0.7)(svelte@5.0.0-next.26)(typescript@5.3.3)(vite@5.0.10):
resolution: {integrity: sha512-B5h7sRXFmNvZucQlhz8MBsrsYfmVYCtcBUdDGe4ndJyBpD+klvmw31NGqhQp4z6HqxwbSWgaAvjXt/A76cgLIA==}
engines: {node: '>=18.14.1'}
peerDependencies:
astro: ^4.0.0
svelte: ^4.0.0 || ^5.0.0-next.1
dependencies:
'@sveltejs/vite-plugin-svelte': 3.0.1(svelte@5.0.0-next.26)(vite@5.0.10)
astro: 4.0.6(sass@1.69.5)(typescript@5.3.3)
astro: 4.0.7(sass@1.69.5)(typescript@5.3.3)
svelte: 5.0.0-next.26
svelte2tsx: 0.6.27(svelte@5.0.0-next.26)(typescript@5.3.3)
transitivePeerDependencies:
@ -1423,19 +1423,19 @@ packages:
hasBin: true
dev: false
/astro-pagefind@1.3.0(astro@4.0.6):
/astro-pagefind@1.3.0(astro@4.0.7):
resolution: {integrity: sha512-7VqoJnaW301KY+mjf1cGJTfKNI+zjdYxDXtBIE6aD77NKNPrOjxIXllt9Fo3wU84z1sNmaI+LwzK6S0Zm8t9RQ==}
peerDependencies:
astro: ^2.0.4 || ^3.0.0
dependencies:
'@pagefind/default-ui': 1.0.4
astro: 4.0.6(sass@1.69.5)(typescript@5.3.3)
astro: 4.0.7(sass@1.69.5)(typescript@5.3.3)
pagefind: 1.0.4
sirv: 2.0.3
sirv: 2.0.4
dev: false
/astro@4.0.6(sass@1.69.5)(typescript@5.3.3):
resolution: {integrity: sha512-P7CfFqWKzkJozzF6IoOC6qoI2ONndV8P3ULhGDgMiXPL7xVkWI5haTBSpyrcjBx643tVXspIRsSV/v+Cx+CjGw==}
/astro@4.0.7(sass@1.69.5)(typescript@5.3.3):
resolution: {integrity: sha512-K+Ms2AAQvi6yERPuglcI69tnHyTT44JCjzqprSjw3uOwFX7N9obpLgbhmLMH1fPFTgzt3ZD7APjmtDPN51makw==}
engines: {node: '>=18.14.1', npm: '>=6.14.0'}
hasBin: true
dependencies:
@ -1480,7 +1480,7 @@ packages:
mime: 3.0.0
ora: 7.0.1
p-limit: 5.0.0
p-queue: 7.4.1
p-queue: 8.0.1
path-to-regexp: 6.2.1
preferred-pm: 3.1.2
probe-image-size: 7.2.3
@ -1585,8 +1585,8 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
dependencies:
caniuse-lite: 1.0.30001570
electron-to-chromium: 1.4.615
caniuse-lite: 1.0.30001571
electron-to-chromium: 1.4.616
node-releases: 2.0.14
update-browserslist-db: 1.0.13(browserslist@4.22.2)
dev: false
@ -1610,8 +1610,8 @@ packages:
engines: {node: '>=14.16'}
dev: false
/caniuse-lite@1.0.30001570:
resolution: {integrity: sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==}
/caniuse-lite@1.0.30001571:
resolution: {integrity: sha512-tYq/6MoXhdezDLFZuCO/TKboTzuQ/xR5cFdgXPfDtM7/kchBO3b4VWghE/OAi/DV7tTdhmLjZiZBZi1fA/GheQ==}
dev: false
/ccount@2.0.1:
@ -1917,8 +1917,8 @@ packages:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
dev: false
/electron-to-chromium@1.4.615:
resolution: {integrity: sha512-/bKPPcgZVUziECqDc+0HkT87+0zhaWSZHNXqF8FLd2lQcptpmUFwoCSWjCdOng9Gdq+afKArPdEg/0ZW461Eng==}
/electron-to-chromium@1.4.616:
resolution: {integrity: sha512-1n7zWYh8eS0L9Uy+GskE0lkBUNK83cXTVJI0pU3mGprFsbfSdAc15VTFbo+A+Bq4pwstmL30AVcEU3Fo463lNg==}
dev: false
/emoji-regex@10.3.0:
@ -2074,7 +2074,7 @@ packages:
human-signals: 5.0.0
is-stream: 3.0.0
merge-stream: 2.0.0
npm-run-path: 5.1.0
npm-run-path: 5.2.0
onetime: 6.0.0
signal-exit: 4.1.0
strip-final-newline: 3.0.0
@ -3371,8 +3371,8 @@ packages:
resolution: {integrity: sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==}
dev: false
/mrmime@1.0.1:
resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==}
/mrmime@2.0.0:
resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==}
engines: {node: '>=10'}
dev: false
@ -3482,8 +3482,8 @@ packages:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
/npm-run-path@5.1.0:
resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==}
/npm-run-path@5.2.0:
resolution: {integrity: sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
path-key: 4.0.0
@ -3561,17 +3561,17 @@ packages:
p-limit: 3.1.0
dev: false
/p-queue@7.4.1:
resolution: {integrity: sha512-vRpMXmIkYF2/1hLBKisKeVYJZ8S2tZ0zEAmIJgdVKP2nq0nh4qCdf8bgw+ZgKrkh71AOCaqzwbJJk1WtdcF3VA==}
engines: {node: '>=12'}
/p-queue@8.0.1:
resolution: {integrity: sha512-NXzu9aQJTAzbBqOt2hwsR63ea7yvxJc0PwN/zobNAudYfb1B7R08SzB4TsLeSbUCuG467NhnoT0oO6w1qRO+BA==}
engines: {node: '>=18'}
dependencies:
eventemitter3: 5.0.1
p-timeout: 5.1.0
p-timeout: 6.1.2
dev: false
/p-timeout@5.1.0:
resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==}
engines: {node: '>=12'}
/p-timeout@6.1.2:
resolution: {integrity: sha512-UbD77BuZ9Bc9aABo74gfXhNvzC9Tx7SxtHSh1fxvx3jTLLYvmVhiQZZrJzqqU0jKbN32kb5VOKiLEQI/3bIjgQ==}
engines: {node: '>=14.16'}
dev: false
/p-try@2.2.0:
@ -3988,8 +3988,8 @@ packages:
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
dev: false
/reveal.js@5.0.3:
resolution: {integrity: sha512-OR3mXl2E0GviJbi2p21VWD/j6CQbEQj2WU6jaS1RZRzah9CHmPpJR32uvUh7EtckMLOZfuFYGjYA5zImcgwOoA==}
/reveal.js@5.0.4:
resolution: {integrity: sha512-480pVhre9SXWuE4QbDwG0nPrip3TkifflqaKQWF8Ynf4iYIUBfgu5leeMso0srubQsZQ+G2OzktAfAkrvBY0Ww==}
engines: {node: '>=18.0.0'}
dev: false
@ -4159,12 +4159,12 @@ packages:
dependencies:
is-arrayish: 0.3.2
/sirv@2.0.3:
resolution: {integrity: sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==}
/sirv@2.0.4:
resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==}
engines: {node: '>= 10'}
dependencies:
'@polka/url': 1.0.0-next.24
mrmime: 1.0.1
mrmime: 2.0.0
totalist: 3.0.1
dev: false

View file

@ -1,12 +1,19 @@
<script lang="ts">
import type { ChangeEventHandler } from 'svelte/elements';
import type { ChangeEventHandler, UIEventHandler } from 'svelte/elements';
let client = $state<Pagefind>();
let query = $state<string>('');
let limit = $state<number>(10);
let result = $derived(client?.search(query));
const require = (path: string) => import(/* @vite-ignore */path);
function handler(): ChangeEventHandler<HTMLInputElement> {
function sync(): void {
query = new URLSearchParams(window.location.search).get('q') || '';
}
function onInput(): ChangeEventHandler<HTMLInputElement> {
let debounce: number | undefined;
return event => {
@ -20,12 +27,23 @@ function handler(): ChangeEventHandler<HTMLInputElement> {
}
}
function sync() {
const params = new URLSearchParams(window.location.search);
query = params.get('q') || '';
}
function onScroll(): UIEventHandler<Window> {
let throttle = Date.now();
const require = (path: string) => import(/* @vite-ignore */path);
return event => {
const now = Date.now();
if (throttle + 200 > now) return;
const { scrollHeight } = document.documentElement;
const { innerHeight, scrollY } = event.currentTarget;
const distance = scrollHeight - (innerHeight + scrollY);
if (distance < 100) {
limit += 5;
throttle = now;
}
}
}
$effect(() => {
sync();
@ -34,7 +52,9 @@ $effect(() => {
</script>
<svelte:window on:popstate={sync}/>
<svelte:window
on:popstate={sync}
on:scroll={onScroll()}/>
{#snippet tile(data: PagefindDocument)}
<a class="c-search__result" href={data.url}>
@ -53,7 +73,8 @@ $effect(() => {
<h1>Search</h1>
<input class="c-search__input" placeholder="Start typing here!"
bind:value={query}
on:input={handler()}/>
on:input={onInput()}
on:input={() => limit = 10}/>
{#if query && result}
{#await result}
@ -61,7 +82,7 @@ $effect(() => {
{:then {results}}
<section class="c-search__results">
<div>Showing results for "{query}" ({results.length})</div>
{#each results as page (page.id)}
{#each results.slice(0, limit) as page (page.id)}
{#await page.data()}
Loading...
{:then page}