import { createFileRoute, useNavigate } from "@tanstack/react-router"; import { requireSignedIn } from "~/lib/route-guards"; import { useState } from "react"; import { z } from "zod"; import { createRepo, transferableOwners } from "~/fns/repos"; import { useAction } from "~/hooks/use-action"; import { Button } from "~/ui/Button"; import { CheckboxField, SelectField, TextField } from "~/ui/Field"; import { ErrorBanner } from "~/ui/Callout"; import { PageContainer } from "~/ui/PageContainer"; import { Panel } from "~/ui/Panel"; import { Heading } from "~/ui/Heading"; const VISIBILITY = [ { value: "public", label: "Public — anyone can see and clone" }, { value: "private", label: "Private — only you and collaborators" }, ] as const; const MODES = [ { id: "empty", label: "Start fresh" }, { id: "import", label: "Import from a URL" }, ] as const; const searchSchema = z.object({ import: z.string().optional(), name: z.string().optional() }); export const Route = createFileRoute("/new")({ validateSearch: searchSchema, beforeLoad: ({ context, location }) => { requireSignedIn({ context, location }); }, loader: () => transferableOwners(), component: NewRepoPage, }); function NewRepoPage() { const owners = Route.useLoaderData(); const search = Route.useSearch(); const navigate = useNavigate(); const action = useAction(createRepo, { invalidate: false }); const [mode, setMode] = useState<(typeof MODES)[number]["id"]>(search.import ? "import" : "empty"); async function submit(event: React.SubmitEvent) { event.preventDefault(); const form = new FormData(event.currentTarget); const description = String(form.get("description") ?? "").trim(); const result = await action.run({ data: { owner: String(form.get("owner")), name: String(form.get("name") ?? ""), description: description || null, visibility: form.get("visibility") === "private" ? "private" : "public", initReadme: form.get("readme") === "on", importUrl: mode === "import" ? String(form.get("importUrl") ?? "") : null, importToken: mode === "import" ? String(form.get("importToken") ?? "").trim() || null : null, }, }); if (result) await navigate({ to: "/$owner/$repo", params: { owner: result.owner, repo: result.name } }); } return ( Create a repository

Each repository is backed by its own Cloudflare Artifacts repo.

{MODES.map((item) => ( ))}
({ value: owner, label: owner }))} />
{mode === "import" && ( <> )} {mode === "empty" && ( )}
); }