Create flow: session UI + sign out
This commit is contained in:
@@ -34,6 +34,29 @@ function MagicLinkFetchMock({ children }: { children: React.ReactNode }) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
/** Fake marketing page behind the overlay (header “Log in” opens `AuthModalProvider` with this look). */
|
||||
function FakeMarketingPageBehindOverlay({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<div className="relative min-h-[100dvh] overflow-hidden">
|
||||
<div
|
||||
className="absolute inset-0 bg-gradient-to-br from-amber-100 via-white to-amber-50"
|
||||
aria-hidden
|
||||
/>
|
||||
<div className="relative z-0 px-8 py-16">
|
||||
<p className="font-inter max-w-md text-lg text-neutral-800">
|
||||
Placeholder page content — the login overlay portals above this and uses
|
||||
backdrop blur (`blurredYellow`).
|
||||
</p>
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default {
|
||||
title: "Components/Modals/Login",
|
||||
component: Login,
|
||||
@@ -42,61 +65,89 @@ export default {
|
||||
nextjs: {
|
||||
appDirectory: true,
|
||||
navigation: {
|
||||
pathname: "/login",
|
||||
pathname: "/",
|
||||
},
|
||||
},
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
"Full-page style login shell (yellow backdrop) with modal card. Uses magic-link `LoginForm` inside. Matches `/login` and header modal usage.",
|
||||
"**Primary UX:** `AuthModalProvider` opens this as a **popup overlay** on top of the current page — `backdropVariant=\"blurredYellow\"`, `usePortal` (default). **`/login`** is a thin full-page shell: yellow **solid** backdrop, `usePortal={false}`, same `LoginForm` inside.",
|
||||
},
|
||||
},
|
||||
},
|
||||
decorators: [
|
||||
(Story: () => React.ReactNode) => (
|
||||
<MagicLinkFetchMock>
|
||||
<Story />
|
||||
</MagicLinkFetchMock>
|
||||
),
|
||||
],
|
||||
tags: ["autodocs"],
|
||||
};
|
||||
|
||||
/** Matches `AuthModalProvider`: blurred backdrop + portal over whatever route the user was on. */
|
||||
export const HeaderOverlayBlurred = {
|
||||
name: "Header overlay (blurred — default)",
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Same as **Log in** from the site header: `backdropVariant=\"blurredYellow\"`, `usePortal`, card + “Back to home” below.",
|
||||
},
|
||||
},
|
||||
},
|
||||
render: () => (
|
||||
<FakeMarketingPageBehindOverlay>
|
||||
<Login
|
||||
isOpen
|
||||
onClose={() => {}}
|
||||
backdropVariant="blurredYellow"
|
||||
usePortal
|
||||
ariaLabelledBy="login-modal-heading"
|
||||
belowCard={
|
||||
<a
|
||||
href="/"
|
||||
className="font-inter font-normal text-[14px] leading-[20px] text-[var(--color-content-invert-tertiary,#2d2d2d)] text-center hover:opacity-90"
|
||||
>
|
||||
← Back to home
|
||||
</a>
|
||||
}
|
||||
>
|
||||
<Suspense fallback={<p className="font-inter p-6">Loading…</p>}>
|
||||
<LoginForm />
|
||||
</Suspense>
|
||||
</Login>
|
||||
</FakeMarketingPageBehindOverlay>
|
||||
),
|
||||
};
|
||||
|
||||
/** Matches `app/login/page.tsx`: dedicated route, solid yellow, no portal. */
|
||||
export const FullPageRouteSolid = {
|
||||
name: "Full-page route (/login — solid)",
|
||||
parameters: {
|
||||
nextjs: {
|
||||
navigation: { pathname: "/login" },
|
||||
},
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Verify-email **error** links and bookmarks use `/login` with a **solid** backdrop and `usePortal={false}`.",
|
||||
},
|
||||
},
|
||||
},
|
||||
decorators: [
|
||||
(Story: () => React.ReactNode) => (
|
||||
<div className="min-h-[100dvh] bg-[var(--color-surface-inverse-brand-primary)]">
|
||||
<MagicLinkFetchMock>
|
||||
<Story />
|
||||
</MagicLinkFetchMock>
|
||||
<Story />
|
||||
</div>
|
||||
),
|
||||
],
|
||||
tags: ["autodocs"],
|
||||
};
|
||||
|
||||
export const ModalChromeOnly = {
|
||||
name: "Modal (placeholder content)",
|
||||
render: () => (
|
||||
<Login
|
||||
isOpen
|
||||
onClose={() => {}}
|
||||
ariaLabelledBy="login-modal-heading"
|
||||
belowCard={
|
||||
<a
|
||||
href="/"
|
||||
className="font-inter font-normal text-[14px] leading-[20px] text-[var(--color-content-invert-tertiary,#2d2d2d)] text-center hover:opacity-90"
|
||||
>
|
||||
← Back to home
|
||||
</a>
|
||||
}
|
||||
>
|
||||
<p
|
||||
id="login-modal-heading"
|
||||
className="font-inter px-2 py-4 text-[var(--color-content-default-primary)]"
|
||||
>
|
||||
Placeholder body — use "With magic link form" for the real
|
||||
flow.
|
||||
</p>
|
||||
</Login>
|
||||
),
|
||||
};
|
||||
|
||||
export const WithMagicLinkForm = {
|
||||
name: "With magic link form",
|
||||
render: () => (
|
||||
<Login
|
||||
isOpen
|
||||
onClose={() => {}}
|
||||
backdropVariant="solid"
|
||||
usePortal={false}
|
||||
ariaLabelledBy="login-modal-heading"
|
||||
belowCard={
|
||||
<a
|
||||
@@ -114,16 +165,54 @@ export const WithMagicLinkForm = {
|
||||
),
|
||||
};
|
||||
|
||||
export const ModalChromeOnly = {
|
||||
name: "Modal chrome only (placeholder)",
|
||||
render: () => (
|
||||
<div className="min-h-[100dvh] bg-[var(--color-surface-inverse-brand-primary)]">
|
||||
<Login
|
||||
isOpen
|
||||
onClose={() => {}}
|
||||
backdropVariant="solid"
|
||||
usePortal={false}
|
||||
ariaLabelledBy="login-modal-heading"
|
||||
belowCard={
|
||||
<a
|
||||
href="/"
|
||||
className="font-inter font-normal text-[14px] leading-[20px] text-[var(--color-content-invert-tertiary,#2d2d2d)] text-center hover:opacity-90"
|
||||
>
|
||||
← Back to home
|
||||
</a>
|
||||
}
|
||||
>
|
||||
<p
|
||||
id="login-modal-heading"
|
||||
className="font-inter px-2 py-4 text-[var(--color-content-default-primary)]"
|
||||
>
|
||||
Placeholder body — use "Header overlay" or "Full-page
|
||||
route" for the real flow.
|
||||
</p>
|
||||
</Login>
|
||||
</div>
|
||||
),
|
||||
};
|
||||
|
||||
export const FormOnly = {
|
||||
name: "Login form (card inset)",
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Form only, for inspecting copy and layout without the modal chrome. Wrap in `Login` in the app.",
|
||||
"Form only, for inspecting copy and layout without overlay chrome. In the app it is always wrapped by `Login` (modal) or the `/login` page shell.",
|
||||
},
|
||||
},
|
||||
},
|
||||
decorators: [
|
||||
(Story: () => React.ReactNode) => (
|
||||
<div className="min-h-[200px] bg-[var(--color-surface-inverse-brand-primary)] p-8">
|
||||
<Story />
|
||||
</div>
|
||||
),
|
||||
],
|
||||
render: () => (
|
||||
<div className="mx-auto max-w-[560px] rounded-[20px] bg-[var(--color-surface-default-primary)] p-6 shadow-lg">
|
||||
<Suspense fallback={<p className="font-inter">Loading…</p>}>
|
||||
|
||||
Reference in New Issue
Block a user