Add LynkedUp roofing portal: full login + registration auth UI

- Split-screen dark/orange auth shell with animated scan showcase
- Login state machine: social/email, passkey, password, OTP (email/SMS/WhatsApp),
  TOTP, push, try-another-way, forgot-password, terms gate, success
- 4-step registration wizard: Account, Property, Verify, Address
- US-default phone + address with /api/geo lookup (PIN auto-fill / search)
- Roofing-themed content, Inter font, logo from public/image

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-27 18:36:08 +05:30
parent 50b120e184
commit 8c5df83d63
13 changed files with 2520 additions and 21 deletions
+26
View File
@@ -0,0 +1,26 @@
import type { Metadata } from "next";
import "@/components/portal/portal.css";
export const metadata: Metadata = {
title: "Lynkedup Pro Portal",
description:
"Official Lynkedup Pro portal — manage your workspace, payments and documents.",
};
export default function PortalLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap"
rel="stylesheet"
/>
<div className="portal-root">{children}</div>
</>
);
}
+22
View File
@@ -0,0 +1,22 @@
"use client";
import { PortalAside, PanelBrand } from "@/components/portal/parts";
import { LoginFlow } from "@/components/portal/login-flow";
import { CookieBanner } from "@/components/portal/bits";
export default function LoginPage() {
return (
<main className="portal-main">
<span className="portal-grid" />
<div className="portal-split anim-in">
<PortalAside />
<section className="portal-panel">
<div style={{ width: "100%", maxWidth: 420 }}>
<PanelBrand />
<LoginFlow />
</div>
</section>
</div>
<CookieBanner />
</main>
);
}
+22
View File
@@ -0,0 +1,22 @@
"use client";
import { PortalAside, PanelBrand } from "@/components/portal/parts";
import { RegisterFlow } from "@/components/portal/register-flow";
import { CookieBanner } from "@/components/portal/bits";
export default function RegisterPage() {
return (
<main className="portal-main">
<span className="portal-grid" />
<div className="portal-split anim-in">
<PortalAside />
<section className="portal-panel">
<div style={{ width: "100%", maxWidth: 420 }}>
<PanelBrand />
<RegisterFlow />
</div>
</section>
</div>
<CookieBanner />
</main>
);
}