g1t/apps/web/app/routes/new.tsx

61 lines2,266 bytesCodeBlame
1import { Form, redirect } from "react-router";
2
3import type { Route } from "./+types/new";
4import { Button, ErrorText, Field, Input } from "../components/ui";
5import { repos } from "../lib/services.server";
6import { assertSameOrigin, requireUser } from "../lib/session.server";
7
8export function meta({}: Route.MetaArgs) {
9 return [{ title: "New repository · g1t" }];
10}
11
12export function loader({ request, context }: Route.LoaderArgs) {
13 return { user: requireUser(context, request) };
14}
15
16export async function action({ request, context }: Route.ActionArgs) {
17 assertSameOrigin(request);
18 const user = requireUser(context, request);
19 const form = await request.formData();
20 const result = await repos.create(user, {
21 name: String(form.get("name") ?? ""),
22 description: String(form.get("description") ?? ""),
23 isPrivate: form.get("visibility") === "private",
24 });
25 if (!result.ok) return { error: result.error.message };
26 throw redirect(`/${result.value.namespace}/${result.value.name}`);
27}
28
29export default function NewRepo({
30 loaderData,
31 actionData,
32}: Route.ComponentProps) {
33 return (
34 <main className="mx-auto max-w-lg px-4 py-12">
35 <h1 className="text-xl font-semibold">New repository</h1>
36 <Form method="post" className="mt-8 space-y-4">
37 <Field label="Name">
38 <div className="flex items-center gap-2 font-mono text-sm">
39 <span className="text-muted">{loaderData.user.username}/</span>
40 <Input name="name" required autoFocus maxLength={100} />
41 </div>
42 </Field>
43 <Field label="Description (optional)">
44 <Input name="description" maxLength={200} />
45 </Field>
46 <fieldset className="space-y-2 text-sm">
47 <label className="flex items-center gap-2">
48 <input type="radio" name="visibility" value="public" defaultChecked />
49 Public — anyone can see and clone it
50 </label>
51 <label className="flex items-center gap-2">
52 <input type="radio" name="visibility" value="private" />
53 Private — only you
54 </label>
55 </fieldset>
56 <ErrorText>{actionData?.error}</ErrorText>
57 <Button type="submit">Create repository</Button>
58 </Form>
59 </main>
60 );
61}