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 0000000000..ded60e7ef4 Binary files /dev/null and b/frontend/apps/artcraft-webapp/public/images/artcraft-icon.png differ diff --git a/frontend/apps/artcraft-webapp/src/app/app.tsx b/frontend/apps/artcraft-webapp/src/app/app.tsx index d2651c9390..78c016a82d 100644 --- a/frontend/apps/artcraft-webapp/src/app/app.tsx +++ b/frontend/apps/artcraft-webapp/src/app/app.tsx @@ -20,6 +20,8 @@ import Pricing from "../pages/pricing"; import Support from "../pages/support/support"; import Login from "../pages/login"; import Signup from "../pages/signup"; +import SetPassword from "../pages/set-password"; +import { AuthLayout } from "../components/auth"; import ForgotPassword, { VerifyReset } from "../pages/forgot-password"; import Welcome from "../pages/welcome"; import Onboarding from "../pages/onboarding"; @@ -118,9 +120,14 @@ export function App() { <> - {/* 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. */} +