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 <strong>{search}</strong>.
80 </p>
81 ) : (
82 <p>No repositories yet.</p>
83 )}
84 </div>
85 ) : (
86 <ul class="repo-list">
87 {repos.map((repo) => (
88 <li class="repo-card">
89 <div class="repo-card-main">
90 <div class="repo-card-title">
91 <a
92 href={`/${repo.name}`}
93 class="repo-name"
94 >
95 {repo.name}
96 </a>
97 {repo.is_pinned ? (
98 <span class="badge badge-pinned">
99 Pinned
100 </span>
101 ) : null}
102 {repo.is_private ? (
103 <span class="badge badge-private">
104 Private
105 </span>
106 ) : null}
107 </div>
108 {repo.description && (
109 <p class="repo-description">
110 {repo.description}
111 </p>
112 )}
113 </div>
114 <div class="repo-card-meta">
115 <time
116 class="repo-date"
117 datetime={repo.created_at}
118 >
119 {formatDate(repo.created_at)}
120 </time>
121 </div>
122 </li>
123 ))}
124 </ul>
125 )}
126 <Pagination {...pagination} />
127 </div>
128 </Layout>
129 );
130}
131