Mishig victor HF staff commited on
Commit
25a7ba5
1 Parent(s): b3c073e

[Assistants] Add pagination (#772)

Browse files

* [Assistants] Add pagination

* Update src/lib/components/PaginationArrow.svelte

Co-authored-by: Victor Muštar <[email protected]>

* format

* Simplify by using a href

* this statement needs to be reactive

* simplify pagination

* update disabled

* Update src/routes/assistants/+page.server.ts

---------

Co-authored-by: Victor Muštar <[email protected]>

src/lib/components/Pagination.svelte ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { page } from "$app/stores";
3
+ import PaginationArrow from "./PaginationArrow.svelte";
4
+
5
+ export let classNames = "";
6
+ export let numItemsPerPage: number;
7
+ export let numTotalItems: number;
8
+
9
+ const ELLIPSIS_IDX = -1 as const;
10
+
11
+ const numTotalPages = Math.ceil(numTotalItems / numItemsPerPage);
12
+ $: pageIndex = parseInt($page.url.searchParams.get("p") ?? "0");
13
+ $: pageIndexes = getPageIndexes(pageIndex);
14
+
15
+ function getHref(pageIdx: number) {
16
+ const newUrl = new URL($page.url);
17
+ newUrl.searchParams.set("p", pageIdx.toString());
18
+ return newUrl.toString();
19
+ }
20
+
21
+ function getPageIndexes(pageIdx: number) {
22
+ let pageIdxs: number[] = [];
23
+
24
+ const NUM_EXTRA_BUTTONS = 2; // The number of page links to show on either side of the current page link.
25
+
26
+ const minIdx = 0;
27
+ const maxIdx = numTotalPages - 1;
28
+
29
+ pageIdxs = [pageIdx];
30
+
31
+ // forward
32
+ for (let i = 1; i < NUM_EXTRA_BUTTONS + 1; i++) {
33
+ const newPageIdx = pageIdx + i;
34
+ if (newPageIdx > maxIdx) {
35
+ continue;
36
+ }
37
+ pageIdxs.push(newPageIdx);
38
+ }
39
+ if (maxIdx - pageIdxs[pageIdxs.length - 1] > 1) {
40
+ pageIdxs.push(...[ELLIPSIS_IDX, maxIdx]);
41
+ } else if (maxIdx - pageIdxs[pageIdxs.length - 1] === 1) {
42
+ pageIdxs.push(maxIdx);
43
+ }
44
+
45
+ // backward
46
+ for (let i = 1; i < NUM_EXTRA_BUTTONS + 1; i++) {
47
+ const newPageIdx = pageIdx - i;
48
+ if (newPageIdx < minIdx) {
49
+ continue;
50
+ }
51
+ pageIdxs.unshift(newPageIdx);
52
+ }
53
+ if (pageIdxs[0] - minIdx > 1) {
54
+ pageIdxs.unshift(...[minIdx, ELLIPSIS_IDX]);
55
+ } else if (pageIdxs[0] - minIdx === 1) {
56
+ pageIdxs.unshift(minIdx);
57
+ }
58
+ return pageIdxs;
59
+ }
60
+ </script>
61
+
62
+ {#if numTotalPages > 1}
63
+ <nav>
64
+ <ul
65
+ class="flex select-none items-center justify-between space-x-2 text-gray-700 sm:justify-center dark:text-gray-300 {classNames}"
66
+ >
67
+ <li>
68
+ <PaginationArrow
69
+ href={getHref(pageIndex - 1)}
70
+ direction="previous"
71
+ isDisabled={pageIndex - 1 < 0}
72
+ />
73
+ </li>
74
+ {#each pageIndexes as pageIdx}
75
+ <li class="hidden sm:block">
76
+ <a
77
+ class="
78
+ rounded-lg px-2.5 py-1
79
+ {pageIndex === pageIdx
80
+ ? 'bg-gray-50 font-semibold ring-1 ring-inset ring-gray-200 dark:bg-gray-800 dark:text-yellow-500 dark:ring-gray-700'
81
+ : ''}
82
+ "
83
+ class:pointer-events-none={pageIdx === ELLIPSIS_IDX || pageIndex === pageIdx}
84
+ href={getHref(pageIdx)}
85
+ >
86
+ {pageIdx === ELLIPSIS_IDX ? "..." : pageIdx + 1}
87
+ </a>
88
+ </li>
89
+ {/each}
90
+ <li>
91
+ <PaginationArrow
92
+ href={getHref(pageIndex + 1)}
93
+ direction="next"
94
+ isDisabled={pageIndex + 1 >= numTotalPages}
95
+ />
96
+ </li>
97
+ </ul>
98
+ </nav>
99
+ {/if}
src/lib/components/PaginationArrow.svelte ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import CarbonCaretLeft from "~icons/carbon/caret-left";
3
+ import CarbonCaretRight from "~icons/carbon/caret-right";
4
+
5
+ export let href: string;
6
+ export let direction: "next" | "previous";
7
+ export let isDisabled = false;
8
+ </script>
9
+
10
+ <a
11
+ class="flex items-center rounded-lg px-2.5 py-1 hover:bg-gray-50 dark:hover:bg-gray-800 {isDisabled
12
+ ? 'pointer-events-none opacity-50'
13
+ : ''}"
14
+ {href}
15
+ >
16
+ {#if direction === "previous"}
17
+ <CarbonCaretLeft classNames="mr-1.5" />
18
+ Previous
19
+ {:else}
20
+ Next
21
+ <CarbonCaretRight classNames="ml-1.5" />
22
+ {/if}
23
+ </a>
src/routes/assistants/+page.server.ts CHANGED
@@ -3,6 +3,9 @@ import { ENABLE_ASSISTANTS } from "$env/static/private";
3
  import { collections } from "$lib/server/database.js";
4
  import type { Assistant } from "$lib/types/Assistant";
5
  import { redirect } from "@sveltejs/kit";
 
 
 
6
 
7
  export const load = async ({ url }) => {
8
  if (!ENABLE_ASSISTANTS) {
@@ -10,13 +13,26 @@ export const load = async ({ url }) => {
10
  }
11
 
12
  const modelId = url.searchParams.get("modelId");
 
13
 
14
- // fetch the top 10 assistants sorted by user count from biggest to smallest, filter out all assistants with only 1 users. filter by model too if modelId is provided
 
 
 
 
 
15
  const assistants = await collections.assistants
16
- .find({ userCount: { $gt: 1 }, modelId: modelId ?? { $exists: true }, featured: true })
 
17
  .sort({ userCount: -1 })
18
- .limit(10)
19
  .toArray();
20
 
21
- return { assistants: JSON.parse(JSON.stringify(assistants)) as Array<Assistant> };
 
 
 
 
 
 
22
  };
 
3
  import { collections } from "$lib/server/database.js";
4
  import type { Assistant } from "$lib/types/Assistant";
5
  import { redirect } from "@sveltejs/kit";
6
+ import type { Filter } from "mongodb";
7
+
8
+ const NUM_PER_PAGE = 24;
9
 
10
  export const load = async ({ url }) => {
11
  if (!ENABLE_ASSISTANTS) {
 
13
  }
14
 
15
  const modelId = url.searchParams.get("modelId");
16
+ const pageIndex = parseInt(url.searchParams.get("p") ?? "0");
17
 
18
+ // fetch the top assistants sorted by user count from biggest to smallest, filter out all assistants with only 1 users. filter by model too if modelId is provided
19
+ const filter: Filter<Assistant> = {
20
+ userCount: { $gt: 1 },
21
+ modelId: modelId ?? { $exists: true },
22
+ featured: true,
23
+ };
24
  const assistants = await collections.assistants
25
+ .find(filter)
26
+ .skip(NUM_PER_PAGE * pageIndex)
27
  .sort({ userCount: -1 })
28
+ .limit(NUM_PER_PAGE)
29
  .toArray();
30
 
31
+ const numTotalItems = await collections.assistants.countDocuments(filter);
32
+
33
+ return {
34
+ assistants: JSON.parse(JSON.stringify(assistants)) as Array<Assistant>,
35
+ numTotalItems,
36
+ numItemsPerPage: NUM_PER_PAGE,
37
+ };
38
  };
src/routes/assistants/+page.svelte CHANGED
@@ -10,6 +10,7 @@
10
 
11
  import CarbonAdd from "~icons/carbon/add";
12
  import CarbonHelpFilled from "~icons/carbon/help-filled";
 
13
 
14
  export let data: PageData;
15
 
@@ -124,5 +125,10 @@
124
  No assistants found
125
  {/each}
126
  </div>
 
 
 
 
 
127
  </div>
128
  </div>
 
10
 
11
  import CarbonAdd from "~icons/carbon/add";
12
  import CarbonHelpFilled from "~icons/carbon/help-filled";
13
+ import Pagination from "$lib/components/Pagination.svelte";
14
 
15
  export let data: PageData;
16
 
 
125
  No assistants found
126
  {/each}
127
  </div>
128
+ <Pagination
129
+ classNames="w-full flex justify-center mt-14 mb-4"
130
+ numItemsPerPage={data.numItemsPerPage}
131
+ numTotalItems={data.numTotalItems}
132
+ />
133
  </div>
134
  </div>