diff --git a/apps/host-selfhost/web/auth-layout.tsx b/apps/host-selfhost/web/auth-layout.tsx new file mode 100644 index 000000000..ea784f05c --- /dev/null +++ b/apps/host-selfhost/web/auth-layout.tsx @@ -0,0 +1,90 @@ +import type { ReactNode } from "react"; + +import { Wordmark } from "@executor-js/react/components/wordmark"; + +// Split auth layout for the chromeless pages (setup, login, join): a promo +// panel on the left, the form on the right. The panel follows design.md's +// registry-minimal rules — graph-paper texture, mono eyebrow + index numerals, +// grayscale only — so the first screen a person ever sees speaks the same +// language as the app behind it. Collapses to form-only below lg. +const PANEL_POINTS: ReadonlyArray<{ index: string; title: string; body: string }> = [ + { + index: "01", + title: "Connect", + body: "OpenAPI, GraphQL, and MCP sources become tools your agent can call.", + }, + { + index: "02", + title: "Control", + body: "Policies decide which tools run, which ask first, and which are blocked.", + }, + { + index: "03", + title: "Audit", + body: "Every invocation is recorded, with approvals where they matter.", + }, +]; + +export function AuthLayout(props: { readonly children: ReactNode }) { + return ( +
+ + +
+
+ +
+ {props.children} +
+
+ ); +} diff --git a/apps/host-selfhost/web/login.tsx b/apps/host-selfhost/web/login.tsx index 4d78b9703..4c56287a4 100644 --- a/apps/host-selfhost/web/login.tsx +++ b/apps/host-selfhost/web/login.tsx @@ -5,6 +5,7 @@ import { Input } from "@executor-js/react/components/input"; import { Label } from "@executor-js/react/components/label"; import { authClient } from "./auth-client"; +import { AuthLayout } from "./auth-layout"; import { mcpAuthorizeResumeTarget, safeReturnTo } from "../src/auth/return-to"; // Self-host login: email + password sign-in via Better Auth. On success we @@ -54,12 +55,16 @@ export const LoginPage = () => { }; return ( -
+
-
-

Executor

+
+

+ {mode === "signin" ? "Sign in" : "Join this instance"} +

- {mode === "signin" ? "Sign in to your instance" : "Join with your invite code"} + {mode === "signin" + ? "Welcome back. Use your instance account." + : "Enter the invite code you were given."}

@@ -127,6 +132,6 @@ export const LoginPage = () => {
-
+ ); }; diff --git a/apps/host-selfhost/web/setup.tsx b/apps/host-selfhost/web/setup.tsx index 91418bd21..8bc143d4b 100644 --- a/apps/host-selfhost/web/setup.tsx +++ b/apps/host-selfhost/web/setup.tsx @@ -5,6 +5,7 @@ import { Input } from "@executor-js/react/components/input"; import { Label } from "@executor-js/react/components/label"; import { authClient } from "./auth-client"; +import { AuthLayout } from "./auth-layout"; // First-run setup. A fresh instance has no users, so the first visitor creates // the admin account here. The server admits the first signup into the empty org @@ -32,15 +33,15 @@ export const SetupPage = () => { }; return ( -
+
-
-

Set up Executor

+
+

Set up Executor

- Create the admin account for this instance. + Create the admin account for this instance. You can invite your team once you're in.

@@ -87,6 +88,6 @@ export const SetupPage = () => { {busy ? "Creating…" : "Create admin account"} -
+
); }; diff --git a/packages/react/src/components/mcp-install-card.tsx b/packages/react/src/components/mcp-install-card.tsx index 1ef3f9f8b..0292e4a8b 100644 --- a/packages/react/src/components/mcp-install-card.tsx +++ b/packages/react/src/components/mcp-install-card.tsx @@ -170,7 +170,7 @@ export function McpInstallCard(props: { className?: string }) { ? isDev ? "Uses the repo-local dev CLI from any agent working directory." : "Requires the executor CLI on your PATH." - : "Connect to executor as a remote MCP server over streamable HTTP."; + : "Paste this into Claude Code, Cursor, or any MCP client, and your agent gets every tool you connect here."; const advancedControls = ( @@ -224,9 +224,10 @@ export function McpInstallCard(props: { className?: string }) { key={key} title={label} aria-label={label} + role="img" style={{ zIndex: SUPPORTED_AGENTS.length - index }} className={cn( - "flex h-6 items-center justify-center rounded-md border border-border/60 bg-background px-1.5 transition-[margin] duration-200 ease-[cubic-bezier(0.23,1,0.32,1)]", + "flex h-6 items-center justify-center rounded-md border border-border/60 bg-background px-1.5 text-muted-foreground transition-[margin] duration-200 ease-[cubic-bezier(0.23,1,0.32,1)]", index > 0 && "-ml-2 group-hover/agents:ml-1", )} >