RepoList.tsx
Raw
1import type { RepositoryRow } from "../../db/index.ts";
2import { formatDate } from "../../lib/formatDate.ts";
3import type { SessionUser } from "../../middleware/session.ts";
4import { Layout } from "../layout.tsx";
5import { Pagination, type PaginationInfo } from "../Pagination.tsx";
6
7interface RepoListProps {
8 user: SessionUser | null;
9 repos: RepositoryRow[];
10 search?: string;
11 sort: string;
12 pagination: PaginationInfo;
13}
14
15export function RepoList({
16 user,
17 repos,
18 search,
19 sort,
20 pagination,
21}: RepoListProps) {
22 return (
23 <Layout user={user} title="Repositories">
24 <div class="container">
25 <div class="page-header">
26 <h1 class="page-title">Repositories</h1>
27 {user?.isAdmin && (
28 <a href="/new" class="btn btn-primary">
29 New repository
30 </a>
31 )}
32 </div>
33 <div class="search-row">
34 <form method="GET" action="/" class="search-form">
35 <div class="search-input-wrap">
36 <input
37 type="search"
38 name="q"
39 value={search ?? ""}
40 placeholder="Search repositories…"
41 class="search-input"
42 autocomplete="off"
43 />
44 <button type="submit" class="btn btn-sm">
45 Search
46 </button>
47 </div>
48 </form>
49 <form method="POST" action="/sort">
50 <select
51 name="sort"
52 class="repo-sort-select"
53 data-autosubmit
54 >
55 <option
56 value="created"
57 selected={sort === "created" || undefined}
58 >
59 Newest first
60 </option>
61 <option
62 value="name"
63 selected={sort === "name" || undefined}
64 >
65 Name (A–Z)
66 </option>
67 </select>
68 <noscript>
69 <button type="submit" class="btn btn-sm">
70 Go
71 </button>
72 </noscript>
73 </form>
74 </div>
75 {repos.length === 0 ? (
76 <div class="empty-state">
77 {search ? (
78 <p>
79 No repositories match{" "}
80 <strong safe>{search}</strong>.
81 </p>
82 ) : (
83 <p>No repositories yet.</p>
84 )}
85 </div>
86 ) : (
87 <ul class="repo-list">
88 {repos.map((repo) => (
89 <li class="repo-card">
90 <div class="repo-card-main">
91 <div class="repo-card-title">
92 <a
93 href={`/${repo.name}`}
94 class="repo-name"
95 safe
96 >
97 {repo.name}
98 </a>
99 {repo.is_pinned ? (
100 <span class="badge badge-pinned">
101 Pinned
102 </span>
103 ) : null}
104 {repo.is_private ? (
105 <span class="badge badge-private">
106 Private
107 </span>
108 ) : null}
109 </div>
110 {!!repo.description && (
111 <p class="repo-description" safe>
112 {repo.description}
113 </p>
114 )}
115 </div>
116 <div class="repo-card-meta">
117 <time
118 class="repo-date"
119 datetime={repo.created_at}
120 safe
121 >
122 {formatDate(repo.created_at)}
123 </time>
124 </div>
125 </li>
126 ))}
127 </ul>
128 )}
129 <Pagination {...pagination} />
130 </div>
131 </Layout>
132 );
133}
134