From 19d0813f02ea3cc24009a2300077c90dcfe11562 Mon Sep 17 00:00:00 2001 From: BFlat Date: Tue, 26 May 2026 01:57:05 +0700 Subject: [PATCH] webapp: login signup improvements + Google SSO (#1567) ## Login & Signup improvements + Google sign-in - **Refreshed login & signup pages** - cleaner two-panel design with a looping Seedance 2.0 showcase video alongside the form, the ArtCraft logo, and a back button. Tidied up the related password-reset and welcome screens to match. - **Sign in with Google** - added a "Continue with Google" button to both the login and signup pages. - **Set a password after Google sign-up** - first-time Google users are guided to create a password (so they can also sign in on the desktop app), then continue to the welcome/pricing page. Returning users go straight in. - **Account settings** - the password option now says "Set" for accounts that don't have a password yet (and skips asking for a current one), and "Change" otherwise. --- .../public/images/artcraft-icon.png | Bin 0 -> 2428 bytes frontend/apps/artcraft-webapp/src/app/app.tsx | 13 +- .../src/components/auth/GoogleLoginButton.tsx | 8 +- .../src/components/auth/auth-layout.tsx | 109 +++++++++ .../src/components/auth/auth-showcase.tsx | 45 ++++ .../src/components/auth/index.ts | 2 + .../src/components/auth/signup-form.tsx | 73 +++--- .../settings-modal/AccountSection.tsx | 115 +++++---- .../settings-modal/SettingsModal.tsx | 4 +- .../src/components/topbar/topbar.tsx | 4 +- .../src/components/ui/use-media-query.ts | 18 ++ .../apps/artcraft-webapp/src/lib/session.ts | 12 +- .../pages/forgot-password/forgot-password.tsx | 10 +- .../pages/forgot-password/verify-reset.tsx | 14 +- .../artcraft-webapp/src/pages/login/login.tsx | 230 ++++++++---------- .../src/pages/set-password/index.ts | 2 + .../src/pages/set-password/set-password.tsx | 194 +++++++++++++++ .../src/pages/signup/signup.tsx | 51 ++-- .../src/pages/welcome/welcome.tsx | 7 +- frontend/libs/api/src/lib/UsersApi.ts | 8 +- 20 files changed, 659 insertions(+), 260 deletions(-) create mode 100644 frontend/apps/artcraft-webapp/public/images/artcraft-icon.png create mode 100644 frontend/apps/artcraft-webapp/src/components/auth/auth-layout.tsx create mode 100644 frontend/apps/artcraft-webapp/src/components/auth/auth-showcase.tsx create mode 100644 frontend/apps/artcraft-webapp/src/components/ui/use-media-query.ts create mode 100644 frontend/apps/artcraft-webapp/src/pages/set-password/index.ts create mode 100644 frontend/apps/artcraft-webapp/src/pages/set-password/set-password.tsx diff --git a/frontend/apps/artcraft-webapp/public/images/artcraft-icon.png b/frontend/apps/artcraft-webapp/public/images/artcraft-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ded60e7ef4deb53397c523888fea8585c27bca51 GIT binary patch literal 2428 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 - {/* Public — no chrome, no auth gate */} - } /> - } /> + {/* Public — no chrome, no auth gate. login/signup share a layout route + so the showcase pane (and its video) stays mounted when toggling + between them. */} + }> + } /> + } /> + + } /> } /> } /> diff --git a/frontend/apps/artcraft-webapp/src/components/auth/GoogleLoginButton.tsx b/frontend/apps/artcraft-webapp/src/components/auth/GoogleLoginButton.tsx index ae0586573e..d54b1fbe25 100644 --- a/frontend/apps/artcraft-webapp/src/components/auth/GoogleLoginButton.tsx +++ b/frontend/apps/artcraft-webapp/src/components/auth/GoogleLoginButton.tsx @@ -57,9 +57,11 @@ export function GoogleLoginButton({ }; return ( -
+
{/* Custom visual button - shown behind */} -
+
{isLoading ? ( - Continue with Google + Continue with Google )}
diff --git a/frontend/apps/artcraft-webapp/src/components/auth/auth-layout.tsx b/frontend/apps/artcraft-webapp/src/components/auth/auth-layout.tsx new file mode 100644 index 0000000000..65de77fda7 --- /dev/null +++ b/frontend/apps/artcraft-webapp/src/components/auth/auth-layout.tsx @@ -0,0 +1,109 @@ +import { ReactNode } from "react"; +import { Outlet, useNavigate } from "react-router-dom"; +import { faArrowLeft } from "@fortawesome/pro-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { TruchetPattern } from "@storyteller/ui-vfx"; +import { AuthShowcase } from "./auth-showcase"; +import { useMediaQuery } from "../ui/use-media-query"; + +/** + * Persistent shell for the auth pages. Rendered as a layout route so the + * showcase pane (and its video) stays mounted while the form pane swaps + * between login and signup via — toggling between the two no longer + * reloads the showcase video from the start. Each page renders its own header + * (AuthHeader) and footer (AuthFooter) into the outlet. + */ +export const AuthLayout = () => { + // Only mount the showcase on wide screens (matches the `lg` breakpoint) so + // mobile never downloads the demo videos. + const showShowcase = useMediaQuery("(min-width: 1024px)"); + const navigate = useNavigate(); + + const handleBack = () => { + navigate("/"); + }; + + return ( +
+
+ +
+ +
+ +
+ {/* Form pane — only the inner content swaps per route (via Outlet), so + this pane and the showcase beside it stay mounted across the + login/signup toggle. */} +
+ + +
+
+ +
+
+ +
+ © {new Date().getFullYear()} ArtCraft. All rights reserved. +
+
+ + {/* Showcase pane (desktop only) */} + {showShowcase && ( +
+ +
+ )} +
+
+ ); +}; + +interface AuthHeaderProps { + title: string; + subtitle: string; +} + +export const AuthHeader = ({ title, subtitle }: AuthHeaderProps) => ( +
+ ArtCraft +

{title}

+

{subtitle}

+
+); + +export const AuthFooter = ({ children }: { children: ReactNode }) => ( +
{children}
+); diff --git a/frontend/apps/artcraft-webapp/src/components/auth/auth-showcase.tsx b/frontend/apps/artcraft-webapp/src/components/auth/auth-showcase.tsx new file mode 100644 index 0000000000..9335fe28ed --- /dev/null +++ b/frontend/apps/artcraft-webapp/src/components/auth/auth-showcase.tsx @@ -0,0 +1,45 @@ +const FEATURED_VIDEO_URL = + "https://player.vimeo.com/video/1169289718?background=1&autoplay=1&loop=1&muted=1"; + +export const AuthShowcase = () => { + return ( +
+ {/* Vimeo background embed (no controls) scaled to cover the pane. The + iframe is forced to 16:9 and sized to the larger cover dimension via + container-query units, then centered so the overflow crops evenly. */} +