Extract AuthLayout component and polish auth UI

Shared layout for setup, login, and callback pages with consistent
styling. Add GitHub mark icon to action buttons. Document dev server
commands in CLAUDE.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-03-02 20:19:15 -05:00
parent 4d362f320c
commit f1bf37349d
4 changed files with 99 additions and 36 deletions

View file

@ -1,5 +1,10 @@
# Arc
## Dev servers
1. `arc serve --demo` — starts the Rust API server in demo mode
2. `cd apps/arc-web && bun run dev` — starts the React dev server
## API workflow
The OpenAPI spec at `openapi/arc-api.yaml` is the source of truth for the arc-api HTTP interface.

View file

@ -0,0 +1,38 @@
import type { ReactNode } from "react";
function ArcLogo({ className }: { className?: string }) {
return (
<img
src="/logo.svg"
alt="Arc"
className={className}
draggable={false}
/>
);
}
export function AuthLayout({
children,
footer,
}: {
children: ReactNode;
footer?: ReactNode;
}) {
return (
<div className="flex min-h-screen flex-col items-center justify-center bg-atmosphere px-4">
<div className="w-full max-w-sm">
<div className="mb-8 flex justify-center">
<ArcLogo className="h-12 w-12" />
</div>
<div className="rounded-xl border border-line bg-panel/80 p-8 shadow-lg backdrop-blur-sm">
{children}
</div>
{footer && (
<div className="mt-4 text-center text-xs text-fg-muted">
{footer}
</div>
)}
</div>
</div>
);
}

View file

@ -1,4 +1,5 @@
import { redirect } from "react-router";
import { AuthLayout } from "../components/auth-layout";
import { getGitHubOAuth, generateState } from "../lib/github.server";
import type { Route } from "./+types/auth-login";
@ -16,21 +17,30 @@ export function action({ request }: Route.ActionArgs) {
export default function AuthLogin() {
return (
<div className="flex min-h-screen items-center justify-center bg-page">
<div className="w-full max-w-md rounded-lg border border-line-strong bg-panel p-8 shadow-sm">
<h1 className="text-xl font-semibold text-fg">Sign in to Arc</h1>
<p className="mt-2 text-sm text-fg-muted">
Authenticate with your GitHub account to continue.
</p>
<form method="POST" className="mt-6">
<button
type="submit"
className="w-full rounded-md bg-teal-600 px-4 py-2 text-sm font-medium text-white hover:bg-teal-500 focus:outline-2 focus:outline-offset-2 focus:outline-teal-500"
>
Sign in with GitHub
</button>
</form>
</div>
</div>
<AuthLayout>
<h1 className="text-center text-lg font-semibold text-fg">
Sign in to Arc
</h1>
<p className="mt-2 text-center text-sm text-fg-3">
Authenticate with your GitHub account to continue.
</p>
<form method="POST" className="mt-6">
<button
type="submit"
className="flex w-full items-center justify-center gap-2 rounded-lg bg-teal-500 px-4 py-2.5 text-sm font-medium text-white transition-colors hover:bg-teal-300"
>
<GitHubMark />
Sign in with GitHub
</button>
</form>
</AuthLayout>
);
}
function GitHubMark() {
return (
<svg width="18" height="18" viewBox="0 0 16 16" fill="currentColor">
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z" />
</svg>
);
}

View file

@ -1,4 +1,5 @@
import { redirect } from "react-router";
import { AuthLayout } from "../components/auth-layout";
import { isGitHubAppConfigured } from "../lib/github.server";
import type { Route } from "./+types/setup";
@ -35,26 +36,35 @@ export default function Setup({ loaderData }: Route.ComponentProps) {
const { manifest } = loaderData;
return (
<div className="flex min-h-screen items-center justify-center bg-page">
<div className="w-full max-w-md rounded-lg border border-line-strong bg-panel p-8 shadow-sm">
<h1 className="text-xl font-semibold text-fg">Set up Arc</h1>
<p className="mt-2 text-sm text-fg-muted">
Register a GitHub App to enable OAuth login and repository access.
</p>
<form
method="POST"
action="https://github.com/settings/apps/new"
className="mt-6"
<AuthLayout>
<h1 className="text-center text-lg font-semibold text-fg">
Set up Arc
</h1>
<p className="mt-2 text-center text-sm text-fg-3">
Register a GitHub App to enable OAuth login and repository access.
</p>
<form
method="POST"
action="https://github.com/settings/apps/new"
className="mt-6"
>
<input type="hidden" name="manifest" value={manifest} />
<button
type="submit"
className="flex w-full items-center justify-center gap-2 rounded-lg bg-teal-500 px-4 py-2.5 text-sm font-medium text-white transition-colors hover:bg-teal-300"
>
<input type="hidden" name="manifest" value={manifest} />
<button
type="submit"
className="w-full rounded-md bg-teal-600 px-4 py-2 text-sm font-medium text-white hover:bg-teal-500 focus:outline-2 focus:outline-offset-2 focus:outline-teal-500"
>
Register GitHub App
</button>
</form>
</div>
</div>
<GitHubMark />
Register GitHub App
</button>
</form>
</AuthLayout>
);
}
function GitHubMark() {
return (
<svg width="18" height="18" viewBox="0 0 16 16" fill="currentColor">
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z" />
</svg>
);
}