From 27fd68c8df244cc01510ad52742a943d1b60d043 Mon Sep 17 00:00:00 2001 From: glass beadian Date: Tue, 13 Oct 2026 08:13:33 +0000 Subject: [PATCH] Landing: Enter -> login door, /login deep-link (signin mode), /signup register; onboarding scroll fix --- apps/web/src/app/(main)/onboarding/page.tsx | 7 +++++-- apps/web/src/app/login/page.tsx | 9 +++++++++ apps/web/src/app/page.tsx | 6 +++--- infra/occupymedia/docker-compose.chat.yml | 1 + 4 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 apps/web/src/app/login/page.tsx diff --git a/apps/web/src/app/(main)/onboarding/page.tsx b/apps/web/src/app/(main)/onboarding/page.tsx index 06c7430..2808633 100644 --- a/apps/web/src/app/(main)/onboarding/page.tsx +++ b/apps/web/src/app/(main)/onboarding/page.tsx @@ -65,7 +65,10 @@ function SignInForm({ onSwitch }: { onSwitch: () => void }): React.ReactElement export default function OnboardingPage(): React.ReactElement { const { status, session, register, adoptToken, logout } = useAuth(); const offline = status === "offline"; - const [mode, setMode] = useState<"register" | "signin">("register"); + // /login deep-links here in sign-in mode; the default entry is create-account. + const [mode, setMode] = useState<"register" | "signin">( + typeof window !== "undefined" && window.location.search.includes("mode=signin") ? "signin" : "register", + ); const [step, setStep] = useState(0); const [name, setName] = useState(""); // Collectives opt-in (operator reorder #2): default OFF = solo account. @@ -148,7 +151,7 @@ export default function OnboardingPage(): React.ReactElement { // Signed-in visitors who land here (e.g. from the sidebar) get a way out rather than a second registration form. if (status === "authenticated" && session !== null && step === 0) { return ( -
+

You're signed in

diff --git a/apps/web/src/app/login/page.tsx b/apps/web/src/app/login/page.tsx new file mode 100644 index 0000000..d0f8cc4 --- /dev/null +++ b/apps/web/src/app/login/page.tsx @@ -0,0 +1,9 @@ +import { redirect } from "next/navigation"; + +/** + * /login — the sign-in door. The onboarding page holds both forms; this route + * deep-links into sign-in mode (register stays the default at /signup). + */ +export default function LoginRedirect(): React.ReactElement { + redirect("/onboarding?mode=signin"); +} diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx index 4d842f4..88e390c 100644 --- a/apps/web/src/app/page.tsx +++ b/apps/web/src/app/page.tsx @@ -88,7 +88,7 @@ function ManualLanding(): React.ReactElement { useEffect(() => { const onKey = (e: KeyboardEvent): void => { if (e.key === "Enter" && e.target === document.body && !e.shiftKey) { - router.push(status === "authenticated" ? "/streams" : "/onboarding"); + router.push(status === "authenticated" ? "/streams" : "/login"); } }; window.addEventListener("keydown", onKey); @@ -133,7 +133,7 @@ function ManualLanding(): React.ReactElement { ))}

{status === "authenticated" @@ -158,7 +158,7 @@ function ManualLanding(): React.ReactElement { // create-account forms. A join link itself arrives from outside // (the only /join route is /join/[token]); starting/solo need the // same forms, so one destination is honest for all three. - const href = "/onboarding"; + const href = "/onboarding?mode=register"; return (
  • 100.117.210.52:6167 restart: unless-stopped