// Sign Up — invite-code gated. User pastes/types their invite, gives email + // optional name, hits "Create my workspace." Magic-link delivery on submit. // OAuth is offered too but the invite is still required. function SignUp() { const [code, setCode] = React.useState(""); const [email, setEmail] = React.useState(""); const [name, setName] = React.useState(""); const [submitting, setSubmitting] = React.useState(false); const [created, setCreated] = React.useState(false); const [codeState, setCodeState] = React.useState("idle"); // idle | checking | ok | bad // Validate the invite code shape (V-XXXXXX, case-insensitive) and pretend to // verify with a debounce so the UI feels alive even with no backend. React.useEffect(() => { const c = code.trim().toLowerCase(); if (!c) { setCodeState("idle"); return undefined; } const looksValid = /^v-?[a-z0-9]{4,8}$/.test(c); if (!looksValid) { setCodeState("bad"); return undefined; } setCodeState("checking"); const t = setTimeout(() => setCodeState("ok"), 600); return () => clearTimeout(t); }, [code]); const emailValid = /\S+@\S+\.\S+/.test(email); const valid = emailValid && codeState === "ok"; const handleSubmit = (e) => { e.preventDefault(); if (!valid || submitting) return; setSubmitting(true); setTimeout(() => { setSubmitting(false); setCreated(true); }, 800); }; return (
{created ? ( ) : ( <>
You're invited

Create your workspace.

Paste your invite code and the email it came to. We'll have you building in seconds.

setCode(e.target.value)} maxLength={12} style={{ paddingRight: 44 }} />
setEmail(e.target.value)} />
setName(e.target.value)} />
or continue with

By creating a workspace you agree to our Terms and Privacy Policy.

Already have an account? Sign in →
)}
); } function CodeStatus({ state }) { const wrap = { position: "absolute", right: 14, top: "50%", transform: "translateY(-50%)", display: "flex", alignItems: "center", gap: 6, fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.06em", textTransform: "uppercase", pointerEvents: "none", }; if (state === "idle") return null; if (state === "checking") return ( ); if (state === "bad") return ( ); if (state === "ok") return ( Valid ); return null; } // Confirmation — we've sent the magic link AND provisioned a workspace. // Small celebratory beat: "Welcome, " if given, else "You're in." function CreatedConfirmation({ email, name }) { return (
Workspace ready

{name ? <>Welcome, {name}. : <>You're in.}

We sent a sign-in link to {email}. Tap it on this device to step inside your workspace.

While you're waiting on the email — your workspace lives at{" "} {(name || email.split("@")[0] || "you").toLowerCase().replace(/[^a-z0-9-]/g, "")}.vibn.app . We'll send you the keys.
Already opened the email? Continue here →
); } ReactDOM.createRoot(document.getElementById("root")).render();