|
5 | 5 | import { Box, ReactiveQueryParam } from '@sveltejs/site-kit/reactivity'; |
6 | 6 | import { onMount } from 'svelte'; |
7 | 7 | import SearchWorker from './packages-worker.ts?worker'; |
| 8 | + import { stopPropagation } from 'svelte/legacy'; |
| 9 | + import Pagination from './pagination.svelte'; |
8 | 10 |
|
9 | 11 | const { data } = $props(); |
10 | 12 |
|
11 | 13 | const query_qp = new ReactiveQueryParam<string>('query'); |
12 | 14 | const page_qp = new ReactiveQueryParam<number>('page', { |
13 | 15 | encode: (v) => v.toString(), |
14 | | - decode: (v) => +v |
| 16 | + decode: (v) => Math.max(1, v.length ? +v : 1) |
15 | 17 | }); |
16 | 18 | const tags_qp = new ReactiveQueryParam<string[]>('tags', { |
17 | 19 | encode: (v) => v.join(','), |
|
63 | 65 | tags_qp.current; |
64 | 66 | page_qp.current; |
65 | 67 |
|
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; |
83 | 73 | } |
| 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 | + }); |
84 | 87 | }); |
85 | 88 |
|
86 | 89 | const number_formatter = Intl.NumberFormat(); |
|
103 | 106 | <h1 class="visually-hidden">Packages</h1> |
104 | 107 |
|
105 | 108 | <div class="container"> |
106 | | - <div class="toc-container" style="order: 1"> |
| 109 | + <div class="toc-container"> |
107 | 110 | <nav aria-label="Docs"> |
108 | 111 | <ul class="sidebar"> |
109 | 112 | {#each [{ tag: 'all', short_title: 'All' }].concat(data.tags) as tag} |
|
165 | 168 | </li> |
166 | 169 | {/each} |
167 | 170 | </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 | | - > |
181 | | - {/each} |
182 | | - </div> |
183 | 171 | </nav> |
184 | 172 | </div> |
185 | 173 |
|
186 | 174 | <div class="page content"> |
187 | 175 | <h1>Packages</h1> |
188 | 176 |
|
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}> |
213 | 207 | <Icon name="close" /> |
214 | 208 | <kbd>Esc</kbd> |
215 | 209 | </button> --> |
216 | | - </div> |
| 210 | + </div> |
217 | 211 |
|
| 212 | + <div class="posts"> |
218 | 213 | {#each registry.current as pkg} |
219 | 214 | <article data-pubdate={pkg.updated}> |
220 | 215 | <a |
|
286 | 281 | {/each} |
287 | 282 | </div> |
288 | 283 |
|
| 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 | + |
289 | 303 | <!-- <ul class="feed"> |
290 | 304 | {#each [{ tag: 'all', short_title: 'All' }].concat(data.tags) as tag} |
291 | 305 | {@const link = new URL(page.url)} |
|
391 | 405 | } |
392 | 406 |
|
393 | 407 | .input-group { |
394 | | - position: relative; |
| 408 | + display: flex; |
| 409 | + align-items: center; |
| 410 | + gap: 1rem; |
395 | 411 | flex: 1; |
396 | 412 |
|
| 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 | +
|
397 | 434 | input { |
398 | | - font: var(--sk-font-ui-large); |
| 435 | + font: var(--sk-font-ui-medium); |
399 | 436 | width: 100%; |
400 | | - padding: var(--padding) 6rem var(--padding) calc(var(--padding) - 0.5rem); |
401 | | - height: 6rem; |
402 | | - border: none; |
403 | | - flex-shrink: 0; |
404 | 437 | color: var(--sk-fg-1); |
405 | | - border-bottom: 1px solid var(--sk-border); |
406 | 438 | background: inherit; |
| 439 | + border: none; |
| 440 | + outline: none; |
407 | 441 |
|
408 | 442 | &::placeholder { |
409 | 443 | color: var(--sk-fg-4); |
410 | 444 | opacity: 0.5; |
411 | 445 | } |
412 | | - |
413 | | - &:focus-visible { |
414 | | - outline-offset: -2px; |
415 | | - } |
416 | 446 | } |
417 | 447 |
|
418 | 448 | button { |
|
425 | 455 |
|
426 | 456 | &:hover, |
427 | 457 | &:focus { |
428 | | - color: var(--sk-fg-3); |
| 458 | + color: var(--sk-fg-1); |
429 | 459 | } |
430 | 460 |
|
431 | 461 | &:focus-visible { |
|
434 | 464 | } |
435 | 465 | } |
436 | 466 |
|
| 467 | + .posts { |
| 468 | + display: flex; |
| 469 | + flex-direction: column; |
| 470 | + margin-block-start: 4rem; |
| 471 | + } |
| 472 | +
|
437 | 473 | h2 { |
438 | 474 | display: inline-block; |
439 | 475 | color: var(--sk-fg-1); |
|
500 | 536 |
|
501 | 537 | .pagination { |
502 | 538 | display: flex; |
| 539 | + justify-content: center; |
503 | 540 |
|
504 | | - a { |
| 541 | + span { |
| 542 | + opacity: 0.5; |
| 543 | + } |
| 544 | +
|
| 545 | + button, |
| 546 | + span { |
| 547 | + width: 2rem; |
| 548 | + text-align: center; |
505 | 549 | font: var(--sk-font-ui-medium); |
506 | 550 | } |
507 | 551 |
|
508 | | - a[aria-current='true'] { |
| 552 | + button[aria-current='true'] { |
509 | 553 | color: var(--sk-fg-accent); |
510 | 554 | text-decoration: underline; |
511 | 555 | } |
|
525 | 569 | } |
526 | 570 |
|
527 | 571 | .toc-container { |
528 | | - background: var(--sk-bg-2); |
529 | 572 | display: none; |
530 | | - |
531 | | - :root.dark & { |
532 | | - background: var(--sk-bg-0); |
533 | | - } |
534 | 573 | } |
535 | 574 |
|
536 | 575 | @media (min-width: 832px) { |
|
0 commit comments