ReleaseList.tsx
⎇
Raw
1import type { ReleaseRow, RepositoryRow } from "../../db/index.ts";
2import type { SessionUser } from "../../middleware/session.ts";
3import {
4 markdownToPlaintext,
5 renderMarkdown,
6} from "../../services/markdown.ts";
7import { Layout } from "../layout.tsx";
8import { Pagination, type PaginationInfo } from "../Pagination.tsx";
9import { RepoHeader } from "../repos/RepoHeader.tsx";
10import { RepoNav } from "../repos/RepoNav.tsx";
11
12interface ReleaseListProps {
13 user: SessionUser | null;
14 repo: RepositoryRow;
15 releases: (ReleaseRow & { asset_count: number })[];
16 pagination: PaginationInfo;
17}
18
19function NotesPreview({ notes }: { notes: string }) {
20 const plaintext = markdownToPlaintext(notes);
21 return (
22 <details class="notes-expand">
23 <summary class="notes-toggle">
24 <div class="notes-preview">{plaintext}</div>
25 <span class="notes-toggle-label" />
26 </summary>
27 <div class="notes-full markdown-body">{renderMarkdown(notes)}</div>
28 </details>
29 );
30}
31
32export function ReleaseList({
33 user,
34 repo,
35 releases,
36 pagination,
37}: ReleaseListProps) {
38 return (
39 <Layout user={user} title={`Releases — ${repo.name}`}>
40 <div class="container">
41 <RepoHeader repo={repo} />
42 <RepoNav repo={repo} active="releases" user={user} />
43 <div class="list-header">
44 <h2 class="list-heading">Releases</h2>
45 {user?.isAdmin && (
46 <a
47 href={`/${repo.name}/releases/new`}
48 class="btn btn-primary btn-sm"
49 >
50 New release
51 </a>
52 )}
53 </div>
54 {releases.length === 0 ? (
55 <div class="empty-state">
56 <p>No releases yet.</p>
57 </div>
58 ) : (
59 <ul class="issue-list">
60 {releases.map((release) => (
61 <li class="issue-item">
62 <div class="release-item-header">
63 <div class="release-item-main">
64 <a
65 href={`/${repo.name}/releases/${release.id}`}
66 class="release-item-title"
67 style={`view-transition-name: release-title-${release.id}`}
68 >
69 {release.name || release.tag_name}
70 </a>
71 <div class="release-item-meta">
72 <a
73 href={`/${repo.name}/tree/${release.commit_hash}`}
74 class="monospace"
75 >
76 {release.commit_hash.slice(
77 0,
78 8,
79 )}
80 </a>
81 {release.asset_count > 0 && (
82 <span>
83 {release.asset_count} asset
84 {release.asset_count !== 1
85 ? "s"
86 : ""}
87 </span>
88 )}
89 {release.include_source_code ===
90 1 && (
91 <span>source archives</span>
92 )}
93 </div>
94 </div>
95 <div class="release-item-date">
96 <span class="badge">
97 {release.tag_name}
98 </span>
99 <time datetime={release.created_at}>
100 {new Date(
101 release.created_at,
102 ).toLocaleDateString()}
103 </time>
104 </div>
105 </div>
106 {release.notes && (
107 <div class="release-notes-section">
108 <p class="release-notes-label">
109 Release Notes
110 </p>
111 <NotesPreview notes={release.notes} />
112 </div>
113 )}
114 </li>
115 ))}
116 </ul>
117 )}
118 <Pagination {...pagination} />
119 </div>
120 </Layout>
121 );
122}
123