FileEdit.tsx
Raw
1import type { RepositoryRow } from "../../db/index.ts";
2import type { SessionUser } from "../../middleware/session.ts";
3import { Layout } from "../layout.tsx";
4import { RepoHeader } from "../repos/RepoHeader.tsx";
5import { RepoNav } from "./RepoNav.tsx";
6
7interface FileEditProps {
8 user: SessionUser;
9 repo: RepositoryRow;
10 ref: string;
11 filePath: string;
12 content: string;
13 error?: string;
14 queryError?: string;
15}
16
17export function FileEdit({
18 user,
19 repo,
20 ref: editRef,
21 filePath,
22 content,
23 error,
24 queryError,
25}: FileEditProps) {
26 const parts = filePath.split("/");
27 const filename = parts[parts.length - 1] ?? filePath;
28 return (
29 <Layout user={user} title={`Edit ${repo.name}/${filePath}`}>
30 <div class="container">
31 <RepoHeader repo={repo} />
32 <RepoNav repo={repo} active="code" user={user} />
33 <div class="breadcrumb">
34 <a href={`/${repo.name}/tree/${editRef}`}>{repo.name}</a>
35 {parts.map((part, i) => {
36 const partPath = parts.slice(0, i + 1).join("/");
37 const isLast = i === parts.length - 1;
38 return (
39 <>
40 <span class="breadcrumb-sep">/</span>
41 {isLast ? (
42 <span class="breadcrumb-current">
43 {part}
44 </span>
45 ) : (
46 <a
47 href={`/${repo.name}/tree/${editRef}/${partPath}`}
48 >
49 {part}
50 </a>
51 )}
52 </>
53 );
54 })}
55 </div>
56 <p class="form-hint">
57 WARNING: Line endings are normalized to LF (\n) on save.
58 </p>
59 {(error || queryError) && (
60 <p class="form-error">{error ?? queryError}</p>
61 )}
62 <form
63 method="POST"
64 action={`/${repo.name}/edit/${editRef}/${filePath}`}
65 >
66 <div class="file-blob-header">
67 <span class="file-blob-name">{filename}</span>
68 <div class="file-blob-actions">
69 <a
70 href={`/${repo.name}/blob/${editRef}/${filePath}`}
71 class="btn btn-sm"
72 >
73 Cancel
74 </a>
75 </div>
76 </div>
77 <div class="file-blob-body">
78 <textarea
79 name="content"
80 class="file-edit-textarea"
81 rows="30"
82 spellcheck="false"
83 autocorrect="off"
84 autocapitalize="off"
85 {...{ autocomplete: "off" }}
86 >
87 {content}
88 </textarea>
89 </div>
90 <div class="form-card">
91 <p
92 class="form-hint"
93 style="margin-bottom: var(--space-4);"
94 >
95 Committing directly to <strong>{editRef}</strong>
96 </p>
97 <div class="form-group">
98 <label for="file-path">File path</label>
99 <input
100 id="file-path"
101 name="new_path"
102 type="text"
103 value={filePath}
104 class="mono"
105 maxlength="1000"
106 />
107 </div>
108 <div class="form-group">
109 <label for="message">Commit message</label>
110 <textarea
111 id="message"
112 name="message"
113 rows="3"
114 required
115 >
116 {`Edited ${filename}`}
117 </textarea>
118 </div>
119 <div class="form-actions">
120 <button type="submit" class="btn btn-primary">
121 Commit changes
122 </button>
123 <a
124 href={`/${repo.name}/blob/${editRef}/${filePath}`}
125 class="btn"
126 >
127 Cancel
128 </a>
129 </div>
130 </div>
131 </form>
132 </div>
133 </Layout>
134 );
135}
136