Skip to content

Commit 34ac54a

Browse files
committed
pagination component and minor visual tweaks
1 parent 82275e0 commit 34ac54a

File tree

4 files changed

+225
-88
lines changed

4 files changed

+225
-88
lines changed

apps/svelte.dev/src/routes/(packages)/packages/+page.server.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,26 @@ export const prerender = false;
88
export async function load({ url }) {
99
const query = url.searchParams.get('query');
1010
const tags = (url.searchParams.get('tags') ?? '').split(',').filter(Boolean);
11-
let page = +(url.searchParams.get('page')?.toString() ?? 0);
11+
let page = Math.max(1, +(url.searchParams.get('page')?.toString() ?? 1));
1212

1313
init(registry);
1414

1515
const current_results = search(query, { tags, sort_by: 'popularity' });
1616

1717
const total_pages = Math.ceil(current_results.length / REGISTRY_PAGE_LIMIT);
18+
console.log(page, total_pages);
1819

19-
if (page + 1 > total_pages) {
20-
page = 0;
20+
if (page > total_pages) {
21+
page = 1;
2122

2223
const new_url = new URL(url);
2324
new_url.searchParams.set('page', page + '');
2425
redirect(303, new_url);
2526
}
2627

2728
const current_results_paged = current_results.slice(
28-
page * REGISTRY_PAGE_LIMIT,
29-
page * REGISTRY_PAGE_LIMIT + REGISTRY_PAGE_LIMIT
29+
(page - 1) * REGISTRY_PAGE_LIMIT,
30+
(page - 1) * REGISTRY_PAGE_LIMIT + REGISTRY_PAGE_LIMIT
3031
);
3132

3233
return {

apps/svelte.dev/src/routes/(packages)/packages/+page.svelte

Lines changed: 117 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
import { Box, ReactiveQueryParam } from '@sveltejs/site-kit/reactivity';
66
import { onMount } from 'svelte';
77
import SearchWorker from './packages-worker.ts?worker';
8+
import { stopPropagation } from 'svelte/legacy';
9+
import Pagination from './pagination.svelte';
810
911
const { data } = $props();
1012
1113
const query_qp = new ReactiveQueryParam<string>('query');
1214
const page_qp = new ReactiveQueryParam<number>('page', {
1315
encode: (v) => v.toString(),
14-
decode: (v) => +v
16+
decode: (v) => Math.max(1, v.length ? +v : 1)
1517
});
1618
const tags_qp = new ReactiveQueryParam<string[]>('tags', {
1719
encode: (v) => v.join(','),
@@ -63,24 +65,25 @@
6365
tags_qp.current;
6466
page_qp.current;
6567
66-
if (ready) {
67-
if (worker_first_run) {
68-
worker_first_run = false;
69-
} else {
70-
const id = uid++;
71-
pending.add(id);
72-
73-
worker.postMessage({
74-
type: 'get',
75-
id,
76-
payload: {
77-
query: query_qp.current,
78-
page: page_qp.current,
79-
tags: $state.snapshot(tags_qp.current)
80-
}
81-
});
82-
}
68+
if (!ready) return;
69+
70+
if (worker_first_run) {
71+
worker_first_run = false;
72+
return;
8373
}
74+
75+
const id = uid++;
76+
pending.add(id);
77+
78+
worker.postMessage({
79+
type: 'get',
80+
id,
81+
payload: {
82+
query: query_qp.current,
83+
page: page_qp.current,
84+
tags: $state.snapshot(tags_qp.current)
85+
}
86+
});
8487
});
8588
8689
const number_formatter = Intl.NumberFormat();
@@ -103,7 +106,7 @@
103106
<h1 class="visually-hidden">Packages</h1>
104107

105108
<div class="container">
106-
<div class="toc-container" style="order: 1">
109+
<div class="toc-container">
107110
<nav aria-label="Docs">
108111
<ul class="sidebar">
109112
{#each [{ tag: 'all', short_title: 'All' }].concat(data.tags) as tag}
@@ -165,56 +168,48 @@
165168
</li>
166169
{/each}
167170
</ul>
168-
169-
<div class="pagination">
170-
{#each Array(total_pages.current), i}
171-
{@const link = new URL(page.url)}
172-
{@const _ = link.searchParams.set('page', i + '')}
173-
<a
174-
href={link.pathname + link.search}
175-
aria-current={page_qp.current === i}
176-
onclick={(e) => {
177-
e.preventDefault();
178-
page_qp.current = i;
179-
}}>{i + 1}</a
180-
>&nbsp;
181-
{/each}
182-
</div>
183171
</nav>
184172
</div>
185173

186174
<div class="page content">
187175
<h1>Packages</h1>
188176

189-
<div class="posts">
190-
<div class="controls">
191-
<div class="input-group">
192-
<input
193-
use:forcefocus
194-
onkeydown={(e) => {
195-
if (e.key === 'Enter' && !e.isComposing) {
196-
// const element = modal.querySelector('a[data-has-node]') as HTMLElement | undefined;
197-
// element?.click();
198-
}
199-
}}
200-
bind:value={query_qp.current}
201-
placeholder="Search"
202-
aria-describedby="search-description"
203-
aria-label={'Search'}
204-
spellcheck="false"
205-
/>
206-
207-
<button aria-label="Clear" onclick={() => (query_qp.current = '')}>
208-
<Icon name="close" />
209-
</button>
210-
</div>
211-
212-
<!-- <button class="raised" aria-label="Close" onclick={close}>
177+
<div class="controls">
178+
<label class="input-group">
179+
<Icon name="search" />
180+
<input
181+
use:forcefocus
182+
onkeydown={(e) => {
183+
if (e.key === 'Enter' && !e.isComposing) {
184+
// const element = modal.querySelector('a[data-has-node]') as HTMLElement | undefined;
185+
// element?.click();
186+
}
187+
}}
188+
bind:value={query_qp.current}
189+
placeholder="Search"
190+
aria-describedby="search-description"
191+
aria-label={'Search'}
192+
spellcheck="false"
193+
/>
194+
195+
<button
196+
aria-label="Clear"
197+
onclick={(e) => {
198+
e.stopPropagation();
199+
query_qp.current = '';
200+
}}
201+
>
202+
<Icon name="close" />
203+
</button>
204+
</label>
205+
206+
<!-- <button class="raised" aria-label="Close" onclick={close}>
213207
<Icon name="close" />
214208
<kbd>Esc</kbd>
215209
</button> -->
216-
</div>
210+
</div>
217211

212+
<div class="posts">
218213
{#each registry.current as pkg}
219214
<article data-pubdate={pkg.updated}>
220215
<a
@@ -286,6 +281,25 @@
286281
{/each}
287282
</div>
288283

284+
<div class="pagination">
285+
<Pagination total={total_pages.current} bind:page={page_qp.current}>
286+
{#snippet children(pageItem)}
287+
{#if pageItem.type === 'ellipsis'}
288+
<span>-</span>
289+
{:else}
290+
<button
291+
aria-current={page_qp.current === pageItem.value}
292+
onclick={() => {
293+
page_qp.current = pageItem.value;
294+
}}
295+
>
296+
{pageItem.value}
297+
</button>
298+
{/if}
299+
{/snippet}
300+
</Pagination>
301+
</div>
302+
289303
<!-- <ul class="feed">
290304
{#each [{ tag: 'all', short_title: 'All' }].concat(data.tags) as tag}
291305
{@const link = new URL(page.url)}
@@ -391,28 +405,44 @@
391405
}
392406
393407
.input-group {
394-
position: relative;
408+
display: flex;
409+
align-items: center;
410+
gap: 1rem;
395411
flex: 1;
396412
413+
border-radius: 0.5rem;
414+
padding: 0.5rem 0.5rem 0.5rem 0rem;
415+
margin-block-start: 1rem;
416+
417+
position: relative;
418+
419+
&:has(:focus-visible) {
420+
outline: 2px solid var(--sk-fg-accent);
421+
outline-offset: 4px;
422+
}
423+
424+
/* Border that is not rounded */
425+
&::after {
426+
content: '';
427+
position: absolute;
428+
inset-block-end: 0;
429+
inset-inline: 0;
430+
height: 1px;
431+
background: var(--sk-border);
432+
}
433+
397434
input {
398-
font: var(--sk-font-ui-large);
435+
font: var(--sk-font-ui-medium);
399436
width: 100%;
400-
padding: var(--padding) 6rem var(--padding) calc(var(--padding) - 0.5rem);
401-
height: 6rem;
402-
border: none;
403-
flex-shrink: 0;
404437
color: var(--sk-fg-1);
405-
border-bottom: 1px solid var(--sk-border);
406438
background: inherit;
439+
border: none;
440+
outline: none;
407441
408442
&::placeholder {
409443
color: var(--sk-fg-4);
410444
opacity: 0.5;
411445
}
412-
413-
&:focus-visible {
414-
outline-offset: -2px;
415-
}
416446
}
417447
418448
button {
@@ -425,7 +455,7 @@
425455
426456
&:hover,
427457
&:focus {
428-
color: var(--sk-fg-3);
458+
color: var(--sk-fg-1);
429459
}
430460
431461
&:focus-visible {
@@ -434,6 +464,12 @@
434464
}
435465
}
436466
467+
.posts {
468+
display: flex;
469+
flex-direction: column;
470+
margin-block-start: 4rem;
471+
}
472+
437473
h2 {
438474
display: inline-block;
439475
color: var(--sk-fg-1);
@@ -500,12 +536,20 @@
500536
501537
.pagination {
502538
display: flex;
539+
justify-content: center;
503540
504-
a {
541+
span {
542+
opacity: 0.5;
543+
}
544+
545+
button,
546+
span {
547+
width: 2rem;
548+
text-align: center;
505549
font: var(--sk-font-ui-medium);
506550
}
507551
508-
a[aria-current='true'] {
552+
button[aria-current='true'] {
509553
color: var(--sk-fg-accent);
510554
text-decoration: underline;
511555
}
@@ -525,12 +569,7 @@
525569
}
526570
527571
.toc-container {
528-
background: var(--sk-bg-2);
529572
display: none;
530-
531-
:root.dark & {
532-
background: var(--sk-bg-0);
533-
}
534573
}
535574
536575
@media (min-width: 832px) {

apps/svelte.dev/src/routes/(packages)/packages/packages-worker.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ addEventListener('message', async (event) => {
1111
}
1212

1313
if (type === 'get') {
14-
let { query, page = 0, tags = [] } = payload;
14+
let { query, page = 1, tags = [] } = payload;
1515

1616
const current_results = search(query, { tags });
1717
const total_pages = Math.ceil(current_results.length / REGISTRY_PAGE_LIMIT);
1818

19-
if (page + 1 > total_pages) {
20-
page = 0;
19+
if (page > total_pages) {
20+
page = 1;
2121

2222
console.log('Redirecting to page 0');
2323
postMessage({
@@ -34,8 +34,8 @@ addEventListener('message', async (event) => {
3434
type: 'results',
3535
payload: {
3636
results: current_results.slice(
37-
page * REGISTRY_PAGE_LIMIT,
38-
page * REGISTRY_PAGE_LIMIT + REGISTRY_PAGE_LIMIT
37+
(page - 1) * REGISTRY_PAGE_LIMIT,
38+
(page - 1) * REGISTRY_PAGE_LIMIT + REGISTRY_PAGE_LIMIT
3939
),
4040
total_pages,
4141
query

0 commit comments

Comments
 (0)