-
Notifications
You must be signed in to change notification settings - Fork 131
/
Copy pathList.tsx
126 lines (116 loc) · 4.04 KB
/
List.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Copyright 2024 the JSR authors. All rights reserved. MIT license.
import { PaginationData } from "../util.ts";
import { Head } from "$fresh/src/runtime/head.ts";
import { ChevronRight } from "./icons/ChevronRight.tsx";
import { ComponentChildren } from "preact";
export interface ListDisplayItem {
href: string;
content: ComponentChildren;
}
export function ListDisplay(
{ title, pagination, currentUrl, children }: {
title?: string;
pagination?: PaginationData;
currentUrl?: URL;
children: ListDisplayItem[];
},
) {
return (
<div class="mt-8 border-1.5 border-jsr-cyan-950 rounded overflow-hidden">
{title &&
(
<div class="px-5 py-4 flex items-center justify-between border-b border-jsr-cyan-300 bg-slate-100 leading-none dark:bg-slate-900">
<span class="font-semibold">{title}</span>
<div />
</div>
)}
<ul class="divide-y">
{children.map((item) => (
<li class="border-jsr-cyan-900/10">
<a
href={item.href}
class="flex items-center px-5 py-3 gap-2 hover:bg-jsr-yellow-200 focus:bg-jsr-yellow-200 focus:ring-2 ring-jsr-cyan-700 ring-inset outline-none"
>
{item.content}
<ChevronRight class="text-jsr-cyan-800 flex-shrink-0" />
</a>
</li>
))}
</ul>
{pagination && (
<Pagination
pagination={pagination}
itemsCount={children.length}
currentUrl={currentUrl!}
/>
)}
</div>
);
}
function Pagination(
{ currentUrl, itemsCount, pagination }: {
currentUrl: URL;
itemsCount: number;
pagination: PaginationData;
},
) {
const start = pagination.page * pagination.limit - pagination.limit;
const prevURL = new URL(currentUrl);
prevURL.searchParams.set("page", (pagination.page - 1).toString());
const nextURL = new URL(currentUrl);
nextURL.searchParams.set("page", (pagination.page + 1).toString());
const hasPrevious = pagination.page > 1;
const hasNext = pagination.limit * pagination.page < pagination.total;
return (
<nav
class="flex items-center justify-between border-t border-jsr-cyan-900/10 bg-white px-4 py-3 sm:px-6 dark:bg-slate-900"
aria-label="Pagination"
>
<Head>
{hasPrevious && (
<link rel="prev" href={prevURL.pathname + prevURL.search} />
)}
{hasNext && (
<link
rel="next"
href={nextURL.pathname + nextURL.search}
/>
)}
</Head>
<div class="hidden sm:block">
<p class="text-sm text-gray-700 dark:text-gray-300">
{start + itemsCount === 0 ? "No results found" : (
<>
Showing <span class="font-semibold">{start + 1}</span> to{" "}
<span class="font-semibold">{start + itemsCount}</span>{" "}
results, out of{" "}
<span class="font-semibold">{pagination.total}</span>
</>
)}
</p>
</div>
<div class="flex flex-1 justify-between sm:justify-end">
{pagination.page > 1
? (
<a
href={prevURL.pathname + prevURL.search}
class="relative inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0 select-none dark:text-gray-300 dark:hover:bg-gray-800 dark:bg-gray-900"
>
Previous
</a>
)
: <span />}
{itemsCount >= pagination.limit
? (
<a
href={nextURL.pathname + nextURL.search}
class="relative ml-3 inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0 select-none dark:text-gray-300 dark:hover:bg-gray-800 dark:bg-gray-900"
>
Next
</a>
)
: <span />}
</div>
</nav>
);
}