Authentication

15 blocks

Authentication 01

Preview
npx nateui@latest add SignInSimple
Dark
import Checkbox from '@/components/ui/Checkbox'
import Link from '@/components/ui/Link'
import SignInForm from '@/components/patterns/SignInForm'

const assetBase = 'https://statics.nateui.com/img'

export default function SignInSimple() {
    return (
        <div className="flex min-h-[640px] w-full items-center justify-center px-4 py-10">
            <section
                aria-labelledby="sign-in-simple-title"
                className="w-full max-w-sm"
            >
                <div className="mb-9 text-center">
                    <div className="mx-auto mb-7 flex size-9 items-center justify-center rounded-control bg-card shadow-card">
                        <img
                            alt="NateUI"
                            className="h-5 w-5"
                            src={`${assetBase}/logos/logo-collapsed.svg`}
                        />
                    </div>
                    <h3
                        id="sign-in-simple-title"
                        className="text-2xl font-semibold leading-tight text-foreground"
                    >
                        Sign in to your account
                    </h3>
                    <p className="mt-2 text-muted-foreground">
                        Enter your credentials to continue.
                    </p>
                </div>

                <SignInForm
                    hint={
                        <div className="mb-7 flex flex-wrap items-center justify-between gap-2 mt-4">
                            <Checkbox className="text-sm" name="remember-device">
                                Remember this device
                            </Checkbox>
                            <Link
                                href="#password-recovery"
                                className="shrink-0 text-sm font-medium text-primary"
                            >
                                Forgot password?
                            </Link>
                        </div>
                    }
                />
                <p className="mt-8 text-center text-sm text-muted-foreground">
                    New here?{' '}
                    <Link href="#sign-up" className="font-medium text-primary">
                        Create an account
                    </Link>
                </p>
            </section>
        </div>
    )
}

Authentication 02

Preview
npx nateui@latest add SignInSSO
Dark
import Button from '@/components/ui/Button'
import Link from '@/components/ui/Link'
import Divider from '@/components/composites/Divider'
import SignInForm from '@/components/patterns/SignInForm'

const assetBase = 'https://statics.nateui.com/img'

export default function SignInSSO() {
    return (
        <div className="flex min-h-[640px] w-full items-center justify-center px-4 py-12">
            <section aria-labelledby="sign-in-sso-title" className="w-full max-w-sm">
                <header className="mb-8 text-center">
                    <div className="mx-auto mb-8 flex items-center justify-center">
                        <img
                            alt="NateUI"
                            className="size-8"
                            src={`${assetBase}/logos/logo-collapsed.svg`}
                        />
                    </div>
                    <h3
                        id="sign-in-sso-title"
                        className="text-2xl font-semibold leading-tight text-foreground"
                    >
                        Sign in
                    </h3>
                    <p className="mt-4 text-muted-foreground">
                        Use your email or a connected account.
                    </p>
                </header>

                <div>
                    <SignInForm />

                    <div className="flex items-center gap-2 py-8">
                        <Divider className="my-0" />
                        <span>or</span>
                        <Divider className="my-0" />
                    </div>

                    <div className="space-y-3">
                        <Button
                            block
                            icon={
                                <img
                                    alt=""
                                    className="h-5 w-5 object-contain"
                                    src={`${assetBase}/thumbs/brands/google.png`}
                                />
                            }
                            type="button"
                            variant="default"
                        >
                            Continue with Google
                        </Button>
                        <Button
                            block
                            icon={
                                <svg
                                    aria-hidden="true"
                                    className="h-5 w-5"
                                    fill="currentColor"
                                    viewBox="0 0 24 24"
                                >
                                    <path d="M10.226 17.284c-2.965-.36-5.054-2.493-5.054-5.256 0-1.123.404-2.336 1.078-3.144-.292-.741-.247-2.314.09-2.965.898-.112 2.111.36 2.83 1.01.853-.269 1.752-.404 2.853-.404 1.1 0 1.999.135 2.807.382.696-.629 1.932-1.1 2.83-.988.315.606.36 2.179.067 2.942.72.854 1.101 2 1.101 3.167 0 2.763-2.089 4.852-5.098 5.234.763.494 1.28 1.572 1.28 2.807v2.336c0 .674.561 1.056 1.235.786 4.066-1.55 7.255-5.615 7.255-10.646C23.5 6.188 18.334 1 11.978 1 5.62 1 .5 6.188.5 12.545c0 4.986 3.167 9.12 7.435 10.669.606.225 1.19-.18 1.19-.786V20.63a2.9 2.9 0 0 1-1.078.224c-1.483 0-2.359-.808-2.987-2.313-.247-.607-.517-.966-1.034-1.033-.27-.023-.359-.135-.359-.27 0-.27.45-.471.898-.471.652 0 1.213.404 1.797 1.235.45.651.921.943 1.483.943.561 0 .92-.202 1.437-.719.382-.381.674-.718.944-.943" />
                                </svg>
                            }
                            type="button"
                            variant="default"
                        >
                            Continue with GitHub
                        </Button>
                    </div>
                </div>

                <p className="mt-8 text-center text-muted-foreground">
                    Need an account?{' '}
                    <Link
                        className="font-medium text-primary"
                        href="#create-account"
                    >
                        Create one
                    </Link>
                </p>
            </section>
        </div>
    )
}

Authentication 03

Preview
npx nateui@latest add SignInSignUpSegment
Dark
import { useState } from 'react'
import Button from '@/components/ui/Button'
import Checkbox from '@/components/ui/Checkbox'
import Link from '@/components/ui/Link'
import Segment from '@/components/ui/Segment'
import SignInForm from '@/components/patterns/SignInForm'
import SignUpForm from '@/components/patterns/SignUpForm'

const assetBase = 'https://statics.nateui.com/img'

type AuthMode = 'sign-in' | 'sign-up'

export default function SignInSignUpSegment() {
    const [mode, setMode] = useState<AuthMode>('sign-in')

    return (
        <div className="flex min-h-[720px] w-full items-center justify-center px-4 py-12">
            <section
                aria-labelledby="sign-in-sign-up-segment-title"
                className="w-full max-w-sm"
            >
                <header className="mb-8 text-center">
                    <h3
                        id="sign-in-sign-up-segment-title"
                        className="text-2xl font-semibold leading-tight text-foreground"
                    >
                        Account access
                    </h3>
                    <p className="mt-2 text-muted-foreground">
                        Sign in or create an account to continue.
                    </p>
                </header>

                <Segment
                    aria-label="Account access mode"
                    className="mb-8 w-full"
                    value={mode}
                    onChange={(value) => setMode(value as AuthMode)}
                >
                    <Segment.Item value="sign-up">
                        Create account
                    </Segment.Item>
                    <Segment.Item value="sign-in">Sign in</Segment.Item>
                </Segment>

                {mode === 'sign-in' ? (
                    <SignInForm />
                ) : (
                    <SignUpForm fields={['userName', 'email', 'password']} />
                )}

                <div className="mt-4">
                    <Button
                        block
                        icon={
                            <img
                                alt=""
                                className="h-5 w-5 object-contain"
                                src={`${assetBase}/thumbs/brands/google.png`}
                            />
                        }
                        type="button"
                        variant="default"
                    >
                        Continue with Google
                    </Button>
                </div>
            </section>
        </div>
    )
}

Authentication 04

Preview
npx nateui@latest add SignInCard
Dark
import Button from '@/components/ui/Button'
import Card from '@/components/ui/Card'
import Link from '@/components/ui/Link'
import SignInForm from '@/components/patterns/SignInForm'
import { PiKey } from 'react-icons/pi'

const assetBase = 'https://statics.nateui.com/img'

export default function SignInCard() {
    return (
        <div className="flex min-h-screen w-full items-center justify-center bg-muted px-4 py-8">
            <section aria-labelledby="sign-in-card-title" className="w-full max-w-sm">
                <header className="mb-8 text-center">
                    <img
                        alt="NateUI"
                        className="mx-auto h-8 w-8"
                        src={`${assetBase}/logos/logo-collapsed.svg`}
                    />
                    <h3
                        id="sign-in-card-title"
                        className="mt-4 text-2xl font-semibold"
                    >
                        Sign in to NateUI
                    </h3>
                    <p className="mt-2 text-muted-foreground">
                        Use your account to continue.
                    </p>
                </header>

                <Card bodyClass="p-8">
                    <div className="space-y-4">
                        <Button
                            block
                            icon={
                                <img
                                    alt=""
                                    className="h-5 w-5 object-contain"
                                    src={`${assetBase}/thumbs/brands/google.png`}
                                />
                            }
                            type="button"
                            variant="default"
                        >
                            Continue with Google
                        </Button>
                        <Button
                            block
                            icon={<PiKey aria-hidden="true" />}
                            type="button"
                            variant="default"
                        >
                            Continue with SSO
                        </Button>
                    </div>

                    <div className="my-4 flex items-center gap-3" aria-hidden="true">
                        <div className="flex-1 border-t" />
                        <span className="font-medium uppercase">
                            Or
                        </span>
                        <div className="flex-1 border-t" />
                    </div>

                    <SignInForm
                        hint={
                            <div className="mt-4 mb-5 flex justify-end">
                                <Link
                                    className="font-medium text-primary"
                                    href="#password-reset"
                                >
                                    Forgot password?
                                </Link>
                            </div>
                        }
                        submitText="Sign in with email"
                    />
                </Card>

                <footer className="mt-8 space-y-4 text-center text-muted-foreground">
                    <p>
                        Need an account?{' '}
                        <Link href="#create-account" className="font-medium text-primary">
                            Create one
                        </Link>
                    </p>
                </footer>
            </section>
        </div>
    )
}

Authentication 05

Preview
npx nateui@latest add SignUpEmailPassword
Dark
import Button from '@/components/ui/Button'
import Link from '@/components/ui/Link'
import Divider from '@/components/composites/Divider'
import SignUpForm from '@/components/patterns/SignUpForm'

const assetBase = 'https://statics.nateui.com/img'

export default function SignUpEmailPassword() {
    return (
        <div className="flex min-h-[760px] w-full items-center justify-center px-4 py-12">
            <section
                aria-labelledby="sign-up-email-password-title"
                className="w-full max-w-sm"
            >
                <header className="mb-8 text-center">
                    <div className="mx-auto mb-7 flex items-center justify-center">
                        <img
                            alt=""
                            className="h-9 w-auto dark:hidden"
                            src={`${assetBase}/logos/logo-collapsed.svg`}
                        />
                        <img
                            alt="NateUI"
                            className="hidden h-9 w-auto dark:block"
                            src={`${assetBase}/logos/logo-collapsed-white.svg`}
                        />
                    </div>
                    <h3
                        id="sign-up-email-password-title"
                        className="text-2xl font-semibold text-foreground"
                    >
                        Create an account
                    </h3>
                    <p className="mt-2 text-muted-foreground">
                        Set up your account to continue.
                    </p>
                </header>

                <Button
                    block
                    icon={
                        <img
                            alt=""
                            className="h-5 w-5 object-contain"
                            src={`${assetBase}/thumbs/brands/google.png`}
                        />
                    }
                    type="button"
                    variant="default"
                >
                    Continue with Google
                </Button>

                <div className="flex items-center gap-2 py-7">
                    <Divider className="my-0" />
                    <span className="text-xs text-muted-foreground">or</span>
                    <Divider className="my-0" />
                </div>

                <SignUpForm
                    fields={['email', 'password']}
                    submitText="Create account"
                    submittingText="Creating account..."
                />

                <p className="mt-7 text-center text-sm text-muted-foreground">
                    Have an account?{' '}
                    <Link href="#sign-in" className="font-medium text-foreground">
                        Sign in
                    </Link>
                </p>
            </section>
        </div>
    )
}

Authentication 06

Preview
npx nateui@latest add SignUpSimple
Dark
import Button from '@/components/ui/Button'
import Link from '@/components/ui/Link'
import Divider from '@/components/composites/Divider'
import SignUpForm from '@/components/patterns/SignUpForm'

const assetBase = 'https://statics.nateui.com/img'

export default function SignUpSimple() {
    return (
        <div className="flex min-h-full w-full justify-center px-4 py-10">
            <section
                aria-labelledby="sign-up-simple-title"
                className="w-full max-w-sm"
            >
                <header className="mb-8">
                    <h3
                        id="sign-up-simple-title"
                        className="text-2xl font-semibold text-foreground"
                    >
                        Sign up
                    </h3>
                    <p className="mt-2 text-muted-foreground">
                        Create an account and verify your details to get
                        started. Already have an account?{' '}
                        <Link href="#sign-in" className="font-medium text-foreground">
                            Sign in
                        </Link>
                    </p>
                </header>

                <SignUpForm
                    fields={['email']}
                    submitText="Sign up"
                    submittingText="Signing up..."
                />

                <div className="flex items-center gap-2 py-6">
                    <Divider className="my-0" />
                    <span>or</span>
                    <Divider className="my-0" />
                </div>

                <Button
                    block
                    icon={
                        <img
                            alt=""
                            className="h-5 w-5 object-contain"
                            src={`${assetBase}/thumbs/brands/google.png`}
                        />
                    }
                    type="button"
                    variant="default"
                >
                    Continue with Google
                </Button>

                <p className="mt-8 text-xs text-muted-foreground">
                    By signing up, you agree to the{' '}
                    <Link
                        href="#privacy-policy"
                        className="font-medium text-foreground"
                    >
                        Privacy Policy
                    </Link>{' '}
                    and{' '}
                    <Link
                        href="#terms-of-service"
                        className="font-medium text-foreground"
                    >
                        Terms of Service
                    </Link>
                    .
                </p>
            </section>
        </div>
    )
}

Authentication 07

Preview
npx nateui@latest add VerifyOTP
Dark
import Link from '@/components/ui/Link'
import OTPVerificationForm from '@/components/patterns/OTPVerificationForm'
import { PiArrowLeft } from 'react-icons/pi'

export default function VerifyOTP() {
    return (
        <div className="flex min-h-full w-full items-center justify-center px-4 py-10">
            <section
                aria-labelledby="verify-otp-title"
                className="w-full max-w-90"
            >
                <header className="mb-8">
                    <h3
                        id="verify-otp-title"
                        className="text-2xl font-semibold text-foreground"
                    >
                        Verify OTP
                    </h3>
                    <p className="mt-2 text-muted-foreground">
                        We sent a verification code to user@example.com.
                    </p>
                </header>

                <OTPVerificationForm
                    autoFocus={false}
                    codeLength={6}
                    hint={
                        <p className="mb-4 text-muted-foreground">
                            Didn&apos;t receive it?{' '}
                            <Link
                                href="#resend-code"
                                className="font-medium text-foreground"
                            >
                                Resend code
                            </Link>
                        </p>
                    }
                    inputClassName="h-12"
                    label={null}
                    submitText="Verify"
                    submittingText="Verifying..."
                    height={53}
                />

                <div className="mt-8 text-center">
                    <Link
                        href="#sign-in"
                        className="inline-flex items-center gap-2 font-medium"
                    >
                        <PiArrowLeft aria-hidden="true" className="text-base" />
                        Back to sign in
                    </Link>
                </div>
            </section>
        </div>
    )
}

Authentication 08

Preview
npx nateui@latest add EmailVerificationComplete
Dark
import IconFrame from '@/components/composites/IconFrame'
import Button from '@/components/ui/Button'
import Link from '@/components/ui/Link'
import { PiArrowLeft, PiCheckCircle } from 'react-icons/pi'

export default function EmailVerificationComplete() {
    return (
        <div className="flex min-h-full w-full items-center justify-center px-4 py-10">
            <section
                aria-labelledby="email-verification-complete-title"
                className="w-full max-w-sm text-center"
            >
                <IconFrame 
                    size={48} 
                    className="mx-auto"
                    variant="layered"
                >
                    <PiCheckCircle aria-hidden="true" className="text-2xl" />
                </IconFrame>

                <header className="mt-8">
                    <h3
                        id="email-verification-complete-title"
                        className="text-2xl font-semibold text-foreground"
                    >
                        Verification complete
                    </h3>
                    <p className="text-muted-foreground mt-4">
                        Your email address is verified.
                        Continue to access your account.
                    </p>
                </header>

                <Button block variant="solid" className="mt-8">
                    Continue
                </Button>
                <div className="mt-8">
                    <Link
                        href="#sign-in"
                        className="inline-flex items-center gap-2 font-medium"
                    >
                        <PiArrowLeft aria-hidden="true" className="text-base" />
                        Back to sign in
                    </Link>
                </div>
            </section>
        </div>
    )
}

Authentication 09

Preview
npx nateui@latest add ForgotPassword
Dark
import ForgotPasswordForm from '@/components/patterns/ForgotPasswordForm'
import Link from '@/components/ui/Link'
import { PiArrowLeft } from 'react-icons/pi'

const assetBase = 'https://statics.nateui.com/img'

export default function ForgotPassword() {
    return (
        <div className="flex min-h-full w-full items-center justify-center px-4 py-8">
            <section aria-labelledby="forgot-password-title" className="w-full max-w-sm">
                <header className="mt-4 text-center">
                    <h3 id="forgot-password-title" className="text-2xl font-semibold text-foreground">
                        Forgot password?
                    </h3>
                    <p className="mt-4 text-muted-foreground">
                        Provide the account email and we will send you a recovery instructions email.
                    </p>
                </header>

                <ForgotPasswordForm
                    className="mt-8"
                    emailSent={false}
                    submitText="Email me a reset link"
                    submittingText="Sending reset link..."
                />

                <div className="mt-8 text-center">
                    <Link
                        href="#sign-in"
                        className="inline-flex items-center gap-2 font-medium text-foreground"
                    >
                        <PiArrowLeft aria-hidden="true" className="text-base" />
                        Return to sign in
                    </Link>
                </div>
            </section>
        </div>
    )
}

Authentication 10

Preview
npx nateui@latest add AuthCardBackgroundCentered
Dark
import { useEffect, useRef } from 'react'
import Button from '@/components/ui/Button'
import Card from '@/components/ui/Card'
import Checkbox from '@/components/ui/Checkbox'
import Link from '@/components/ui/Link'
import AuthShellCentered from '@/components/layouts/AuthShellCentered'
import SignInForm from '@/components/patterns/SignInForm'

const assetBase = 'https://statics.nateui.com/img'

const STRAND_COUNT = 22
const STRAND_WIDTH = 1.5
const SAMPLES_PER_STRAND = 72

const RISE = 0.82
const RUN = 0.86
const rotationFor = (width: number, height: number) =>
    -Math.atan2(RISE * height, RUN * width)

const OVERSCAN = 1.02
const SPACING = 0.011

const FAN_START = 0.25
const FAN_END = 1.95
const AMPLITUDE = 0.085
const FREQUENCY = 0.45
const PHASE_STEP = 0.13
const TWIST = 0.22
const BULGE = 0.3

const FLOW_SPEED = 0.22
const EDGE_FADE_IN = 0.24
const EDGE_FADE_OUT = 0.18

const RAMP = [
    [65, 89, 208],
    [200, 79, 192],
    [255, 205, 112],
]

const lerp = (from: number, to: number, ratio: number) => from + (to - from) * ratio

const sampleRamp = (ratio: number) => {
    const scaled = ratio * (RAMP.length - 1)
    const index = Math.max(0, Math.min(RAMP.length - 2, Math.floor(scaled)))
    const from = RAMP[index]
    const to = RAMP[index + 1] ?? from

    return [0, 1, 2]
        .map((channel) =>
            Math.round(lerp(from[channel], to[channel], scaled - index)),
        )
        .join(', ')
}

const strands = Array.from({ length: STRAND_COUNT }, (_, index) => {
    const ratio = STRAND_COUNT <= 1 ? 0 : index / (STRAND_COUNT - 1)

    return {
        phase: PHASE_STEP * (index - (STRAND_COUNT - 1) / 2),
        offset: (ratio - 0.5) * STRAND_COUNT * SPACING,
        solid: sampleRamp(ratio),
    }
})

const FlowLinesBackdrop = () => {
    const canvasRef = useRef<HTMLCanvasElement>(null)

    useEffect(() => {
        const canvas = canvasRef.current

        if (!canvas) {
            return
        }

        const context = canvas.getContext('2d')

        if (!context) {
            return
        }

        let width = 0
        let height = 0
        let frame = 0

        const measure = () => {
            const ratio = Math.min(window.devicePixelRatio || 1, 2)
            const bounds = canvas.getBoundingClientRect()

            width = bounds.width
            height = bounds.height
            canvas.width = Math.max(1, Math.round(width * ratio))
            canvas.height = Math.max(1, Math.round(height * ratio))
            context.setTransform(ratio, 0, 0, ratio, 0, 0)
        }

        const points: { x: number; y: number }[] = Array.from(
            { length: SAMPLES_PER_STRAND + 1 },
            () => ({ x: 0, y: 0 }),
        )

        const draw = (elapsed: number) => {
            context.clearRect(0, 0, width, height)
            context.lineWidth = STRAND_WIDTH
            context.lineCap = 'round'
            context.lineJoin = 'round'

            const midX = width / 2
            const midY = height / 2
            const rotation = rotationFor(width, height)
            const angleCos = Math.cos(rotation)
            const angleSin = Math.sin(rotation)
            
            const span =
                (width * Math.abs(angleCos) + height * Math.abs(angleSin)) *
                OVERSCAN
            const travel = FLOW_SPEED * elapsed
            const frequency = FREQUENCY * Math.PI * 2

            for (const strand of strands) {
                for (let step = 0; step <= SAMPLES_PER_STRAND; step++) {
                    const along = step / SAMPLES_PER_STRAND
                    // Amplitude swells through the middle of the run.
                    const bulge = 1 + BULGE * Math.sin(along * Math.PI)
                    const wave =
                        Math.sin(frequency * along + strand.phase + travel) +
                        TWIST *
                            Math.sin(
                                0.5 * frequency * along -
                                    2 * strand.phase +
                                    0.7 * travel,
                            )

                    const fan = FAN_START + (FAN_END - FAN_START) * along
                    const flatX = (along - 0.5) * span
                    const flatY =
                        strand.offset * height * fan +
                        wave * 0.5 * bulge * AMPLITUDE * height

                    const point = points[step]
                    point.x = midX + flatX * angleCos - flatY * angleSin
                    point.y = midY + flatX * angleSin + flatY * angleCos
                }

                const first = points[0]
                const last = points[points.length - 1]
                
                const gradient = context.createLinearGradient(
                    first.x,
                    first.y,
                    last.x,
                    last.y,
                )

                gradient.addColorStop(0, `rgba(${strand.solid}, 0)`)
                gradient.addColorStop(EDGE_FADE_IN, `rgba(${strand.solid}, 1)`)
                gradient.addColorStop(
                    1 - EDGE_FADE_OUT,
                    `rgba(${strand.solid}, 1)`,
                )
                gradient.addColorStop(1, `rgba(${strand.solid}, 0)`)
                context.strokeStyle = gradient

                context.beginPath()
                context.moveTo(first.x, first.y)

                for (let step = 1; step < points.length - 1; step++) {
                    const current = points[step]
                    const next = points[step + 1]

                    context.quadraticCurveTo(
                        current.x,
                        current.y,
                        (current.x + next.x) / 2,
                        (current.y + next.y) / 2,
                    )
                }

                context.lineTo(last.x, last.y)
                context.stroke()
            }
        }

        const stillness = window.matchMedia('(prefers-reduced-motion: reduce)')
        const observer = new ResizeObserver(() => {
            measure()
            draw(0)
        })

        const run = (timestamp: number) => {
            draw(timestamp / 1000)
            frame = window.requestAnimationFrame(run)
        }

        const start = () => {
            window.cancelAnimationFrame(frame)
            measure()
            draw(0)

            if (stillness.matches) {
                return
            }

            frame = window.requestAnimationFrame(run)
        }

        start()
        observer.observe(canvas)
        stillness.addEventListener('change', start)

        return () => {
            window.cancelAnimationFrame(frame)
            observer.disconnect()
            stillness.removeEventListener('change', start)
        }
    }, [])

    return (
        <canvas
            aria-hidden="true"
            className="pointer-events-none absolute inset-0 h-full w-full opacity-30"
            ref={canvasRef}
        />
    )
}

export default function AuthCardBackgroundCentered() {
    return (
        <AuthShellCentered
            className="relative overflow-hidden bg-card"
            overlay={<FlowLinesBackdrop />}
            header={
                <header className="relative flex items-center justify-center p-4">
                    <img
                        alt=""
                        className="h-7 w-auto dark:hidden"
                        src={`${assetBase}/logos/logo.svg`}
                    />
                    <img
                        alt="NateUI"
                        className="hidden h-7 w-auto dark:block"
                        src={`${assetBase}/logos/logo-white.svg`}
                    />
                </header>
            }
            footer={
                <footer className="relative p-4 text-center text-muted-foreground">
                    Protected by SSO and device verification.
                </footer>
            }
        >
            <section
                aria-labelledby="auth-card-background-centered-title"
                className="relative"
            >
                <Card
                    className="relative isolate bg-transparent after:absolute after:inset-0 after:-z-10 after:rounded-card after:bg-card/20 after:backdrop-blur-sm"
                    bodyClass="p-8"
                >
                    <Button
                        block
                        icon={
                            <img
                                alt=""
                                className="h-5 w-5 object-contain"
                                src={`${assetBase}/thumbs/brands/google.png`}
                            />
                        }
                        type="button"
                        variant="default"
                    >
                        Continue with Google
                    </Button>

                    <div className="my-4 flex items-center gap-2" aria-hidden="true">
                        <div className="flex-1 border-t" />
                        <span className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
                            Or
                        </span>
                        <div className="flex-1 border-t" />
                    </div>

                    <SignInForm
                        hint={
                            <div className="mb-8 mt-4 flex flex-wrap items-center justify-between gap-2">
                                <Checkbox name="remember-device">
                                    Keep me signed in
                                </Checkbox>
                                <Link
                                    className="shrink-0 font-medium text-primary"
                                    href="#password-recovery"
                                >
                                    Forgot password?
                                </Link>
                            </div>
                        }
                    />
                </Card>

                <p className="mt-8 text-center text-muted-foreground">
                    New to NateUI?{' '}
                    <Link href="#sign-up" className="font-medium text-primary">
                        Create an account
                    </Link>
                </p>
            </section>
        </AuthShellCentered>
    )
}

Authentication 11

Preview
npx nateui@latest add AuthTileGridCentered
Dark
import Button from '@/components/ui/Button'
import Link from '@/components/ui/Link'
import Divider from '@/components/composites/Divider'
import AuthShellCentered from '@/components/layouts/AuthShellCentered'
import SignInForm from '@/components/patterns/SignInForm'

const assetBase = 'https://statics.nateui.com/img'

const integrations = [
    { file: 'dropbox.png', cell: 'col-start-[2] row-start-[1]' },
    { file: 'slack.png', cell: 'col-start-[4] row-start-[3]' },
    { file: 'notion.png', cell: 'col-start-[7] row-start-[1]' },
    { file: 'zapier.png', cell: 'col-start-[9] row-start-[3]' },
    { file: 'figma.png', cell: 'col-start-[12] row-start-[2]' },
    { file: 'github.png', cell: 'col-start-[15] row-start-[1]' },
    { file: 'stripe.png', cell: 'col-start-[16] row-start-[3]' },
]

const plates = [
    'col-start-[6] row-start-[2]',
    'col-start-[11] row-start-[3]',
    'col-start-[14] row-start-[2]',
    'col-start-[3] row-start-[2]',
    'col-start-[10] row-start-[1]',
]

export default function AuthTileGridCentered() {
    return (
        <AuthShellCentered
            className="relative overflow-hidden bg-card"
            overlay={
                <div
                    aria-hidden="true"
                    className="pointer-events-none absolute inset-x-0 top-0 flex justify-center mask-b-from-30% mask-x-from-85%"
                >
                    <div className="grid w-fit grid-cols-[repeat(16,64px)] grid-rows-[repeat(4,64px)] bg-[linear-gradient(to_right,var(--color-border)_1px,transparent_1px),linear-gradient(to_bottom,var(--color-border)_1px,transparent_1px)] [background-size:64px_64px]">
                        {plates.map((cell) => (
                            <div
                                key={cell}
                                className={`size-16 bg-primary-soft ${cell}`}
                            />
                        ))}
                        {integrations.map(({ file, cell }) => (
                            <div
                                key={file}
                                className={`flex size-16 items-center justify-center p-4 ${cell}`}
                            >
                                <img
                                    alt=""
                                    className="h-full w-full object-contain"
                                    src={`${assetBase}/thumbs/brands/${file}`}
                                />
                            </div>
                        ))}
                    </div>
                </div>
            }
        >
            <section
                aria-labelledby="auth-tile-grid-centered-title"
                className="relative w-full"
            >
                <h3
                    id="auth-tile-grid-centered-title"
                    className="mb-8 text-center text-2xl font-semibold text-foreground"
                >
                    Sign In
                </h3>

                <SignInForm
                    hint={
                        <div className="mt-4 mb-8 text-right">
                            <Link
                                className="font-medium text-primary"
                                href="#password-recovery"
                            >
                                Forgot password?
                            </Link>
                        </div>
                    }
                    submitText="Log in"
                    submittingText="Logging in..."
                />

                <Divider className="my-8" />

                <Button
                    block
                    icon={
                        <img
                            alt=""
                            className="h-5 w-5 object-contain"
                            src={`${assetBase}/thumbs/brands/google.png`}
                        />
                    }
                    type="button"
                    variant="default"
                >
                    Continue with Google
                </Button>

                <p className="mt-8 text-center text-muted-foreground">
                    Don&apos;t have an account?{' '}
                    <Link className="font-medium text-primary" href="#sign-up">
                        Create an account
                    </Link>
                </p>
            </section>
        </AuthShellCentered>
    )
}

Authentication 12

Preview
npx nateui@latest add AuthSideImage
Dark
import Button from '@/components/ui/Button'
import Checkbox from '@/components/ui/Checkbox'
import Link from '@/components/ui/Link'
import Divider from '@/components/composites/Divider'
import AuthShellSide from '@/components/layouts/AuthShellSide'
import SignInForm from '@/components/patterns/SignInForm'

const assetBase = 'https://statics.nateui.com/img'

export default function AuthSideImage() {
    return (
        <AuthShellSide
            className="h-screen"
            sideContent={
                <aside className="relative hidden flex-1 overflow-hidden rounded-xl lg:flex max-w-[520px]">
                    <img
                        alt=""
                        className="h-full w-full object-cover"
                        src={`${assetBase}/thumbs/misc/img-15.png`}
                    />
                </aside>
            }
        >
            <section aria-labelledby="auth-side-image-title" className="w-full">
                <header className="mb-8">
                    <div className="mb-4 flex items-center">
                        <img
                            alt=""
                            className="h-9 w-auto dark:hidden"
                            src={`${assetBase}/logos/logo-collapsed.svg`}
                        />
                        <img
                            alt="NateUI"
                            className="hidden h-9 w-auto dark:block"
                            src={`${assetBase}/logos/logo-collapsed-white.svg`}
                        />
                    </div>
                    <h3
                        id="auth-side-image-title"
                        className="text-2xl font-semibold leading-tight text-foreground"
                    >
                        Welcome back
                    </h3>
                </header>

                <div className="grid grid-cols-2 gap-4">
                    <Button
                        block
                        icon={
                            <img
                                alt=""
                                className="h-5 w-5 object-contain"
                                src={`${assetBase}/thumbs/brands/google.png`}
                            />
                        }
                        type="button"
                        variant="default"
                    >
                        Google
                    </Button>
                    <Button
                        block
                        icon={
                            <img
                                alt=""
                                className="h-5 w-5 object-contain"
                                src={`${assetBase}/thumbs/brands/github.png`}
                            />
                        }
                        type="button"
                        variant="default"
                    >
                        GitHub
                    </Button>
                </div>

                <div className="flex items-center gap-2 py-4">
                    <Divider className="my-0" />
                    <span>or</span>
                    <Divider className="my-0" />
                </div>

                <SignInForm
                    hint={
                        <div className="mt-4 mb-8 flex flex-wrap items-center justify-between gap-2">
                            <Checkbox name="remember-device">
                                Remember me
                            </Checkbox>
                            <Link
                                className="shrink-0 font-medium text-primary"
                                href="#password-recovery"
                            >
                                Forgot password?
                            </Link>
                        </div>
                    }
                    submitText="Sign in"
                    submittingText="Signing in..."
                />

                <p className="mt-8 text-center text-muted-foreground">
                    New here?{' '}
                    <Link href="#sign-up" className="font-medium text-primary">
                        Create an account
                    </Link>
                </p>
            </section>
        </AuthShellSide>
    )
}

Authentication 13

Preview
npx nateui@latest add AuthCentredSplit
Dark
import Link from '@/components/ui/Link'
import AuthShellCentredSplit from '@/components/layouts/AuthShellCentredSplit'
import SignUpForm from '@/components/patterns/SignUpForm'

const assetBase = 'https://statics.nateui.com/img'

export default function AuthCentredSplit() {
    return (
        <AuthShellCentredSplit
            className="bg-background text-foreground"
            containerClass=" max-w-[950px] mx-auto"
            header={
                <div className="flex w-full items-center">
                    <img
                        alt=""
                        className="h-7 w-auto dark:hidden"
                        src={`${assetBase}/logos/logo.svg`}
                    />
                    <img
                        alt="NateUI"
                        className="hidden h-7 w-auto dark:block"
                        src={`${assetBase}/logos/logo-white.svg`}
                    />
                </div>
            }
            footer={
                <div className="flex w-full flex-col items-center gap-4 text-sm text-muted-foreground sm:flex-row sm:justify-between">
                    <div className="flex items-center gap-2">
                        <span>
                            Copyright &copy; {`${new Date().getFullYear()}`} NateUI, Inc.
                        </span>
                    </div>
                    <div className="flex items-center gap-6">
                        <Link
                            className="text-muted-foreground hover:text-foreground"
                            href="#terms-of-service"
                        >
                            Terms of Service
                        </Link>
                        <Link
                            className="text-muted-foreground hover:text-foreground"
                            href="#privacy-policy"
                        >
                            Privacy Policy
                        </Link>
                    </div>
                </div>
            }
            sideContent={
                <div className="relative flex h-full items-center overflow-hidden bg-primary px-12 py-12 text-primary-foreground">
                    <img
                        alt=""
                        className="pointer-events-none absolute inset-0 h-full w-full object-cover opacity-10 select-none"
                        src={`${assetBase}/thumbs/misc/img-16.png`}
                    />
                    <div className="relative max-w-sm">
                        <p className="font-semibold uppercase tracking-wide text-primary-foreground/90">
                            Start your 30 days free trial
                        </p>
                        <h2 className="mt-4 text-3xl font-semibold leading-tight text-primary-foreground max-w-[300px]">
                            Every customer chat in a single queue
                        </h2>
                        <blockquote className="mt-8 text-base leading-relaxed text-primary-foreground/90">
                            <p>
                                “We were juggling four inboxes and a spreadsheet.
                                First reply is now under an hour.”
                            </p>
                            <footer className="mt-4 font-medium text-primary-foreground">
                                Priya Raman, 
                                <br />
                                Support Lead at Northwind
                            </footer>
                        </blockquote>
                    </div>
                </div>
            }
        >
            <section aria-labelledby="auth-centred-split-title">
                <h3
                    id="auth-centred-split-title"
                    className="mb-8 text-2xl font-semibold text-foreground"
                >
                    Create an account
                </h3>

                <SignUpForm
                    fields={[
                        'email',
                        'userName',
                        'password',
                    ]}
                    submitText="Create my account"
                    submittingText="Creating account..."
                />

                <p className="mt-8 text-center text-muted-foreground">
                    Already have an account?{' '}
                    <Link className="font-medium text-primary" href="#log-in">
                        Sign in
                    </Link>
                </p>
            </section>
        </AuthShellCentredSplit>
    )
}

Authentication 14

Preview
npx nateui@latest add AuthSidePanel
Dark
import Button from '@/components/ui/Button'
import Link from '@/components/ui/Link'
import AuthShellSide from '@/components/layouts/AuthShellSide'
import SignUpForm from '@/components/patterns/SignUpForm'

const assetBase = 'https://statics.nateui.com/img'

const GRID_WIDTH = 'w-[470px]'
const DIVIDER_COLOR = 'divide-white/40'
const SVG_OPACITY = 'opacity-10'

export default function AuthSidePanel() {
    return (
        <AuthShellSide
            className="h-screen"
            sideContent={
                <aside className="relative hidden w-[520px] max-w-[720px] flex-1 overflow-hidden rounded-xl border border-gray-200 bg-primary lg:flex dark:border-gray-800">
                    <div className={`z-10 flex flex-1 flex-col justify-between divide-y ${DIVIDER_COLOR}`}>
                        <div className={`relative flex flex-1 divide-x ${DIVIDER_COLOR}`}>
                            <div className="relative flex-1">
                                <div className="absolute -bottom-1 -right-1 z-20 h-2 w-2 bg-white" />
                            </div>
                            <div className={`relative ${GRID_WIDTH}`}>
                                <div className="absolute left-0 top-0 h-full w-full bg-primary">
                                    <svg
                                        width="100%"
                                        height="100%"
                                        viewBox="0 0 161 161"
                                        fill="none"
                                        xmlns="http://www.w3.org/2000/svg"
                                        className={SVG_OPACITY}
                                        preserveAspectRatio="none"
                                    >
                                        <path d="M50.7645 0.428005V160.572" stroke="white" strokeWidth="0.5px" />
                                        <path d="M80.6943 0.428005V160.572" stroke="white" strokeWidth="0.5px" />
                                        <path d="M110.624 0.386559V160.531" stroke="white" strokeWidth="0.5px" />
                                    </svg>
                                </div>
                            </div>
                            <div className="relative flex-1">
                                <div className="absolute -bottom-1 -left-1 z-20 h-2 w-2 bg-white" />
                            </div>
                        </div>
                        <div className={`z-10 flex divide-x ${DIVIDER_COLOR}`}>
                            <div className="flex-1 bg-primary text-white/30 bg-[repeating-linear-gradient(125deg,_transparent,_transparent_6px,_currentColor_6px,_currentColor_7px)]" />
                            <div className={`relative ${GRID_WIDTH}`}>
                                <div className="absolute bottom-0 left-0 -z-10 h-full w-full bg-primary">
                                    <svg
                                        width="100%"
                                        height="100%"
                                        viewBox="0 0 161 161"
                                        fill="none"
                                        xmlns="http://www.w3.org/2000/svg"
                                        className={SVG_OPACITY}
                                        preserveAspectRatio="none"
                                    >
                                        <g clipPath="url(#auth-side-panel-grid-clip)">
                                            <rect x={11.1172} y={10.9229} width={139.154} height={139.154} stroke="white" strokeWidth="0.5px" strokeLinejoin="round" />
                                            <path d="M50.7645 0.428005V160.572" stroke="white" strokeWidth="0.5px" />
                                            <path d="M80.6943 0.428005V160.572" stroke="white" strokeWidth="0.5px" />
                                            <path d="M110.624 0.386559V160.531" stroke="white" strokeWidth="0.5px" />
                                            <path d="M0.622345 50.5702H160.766" stroke="white" strokeWidth="0.5px" />
                                            <path d="M0.622345 80.5H160.766" stroke="white" strokeWidth="0.5px" />
                                            <path d="M0.622345 110.43H160.766" stroke="white" strokeWidth="0.5px" />
                                            <circle cx={80.6943} cy={80.5} r={69.5771} stroke="white" strokeWidth="0.5px" />
                                            <ellipse cx={80.6943} cy={80.5} rx={42.3682} ry={42.3682} stroke="white" strokeWidth="0.5px" />
                                            <ellipse cx={80.6943} cy={80.5} rx={29.9298} ry={29.9298} stroke="white" strokeWidth="0.5px" />
                                            <path d="M11.1172 10.9229L150.271 150.077" stroke="white" strokeWidth="0.5px" />
                                            <path d="M150.271 10.9229L11.1172 150.077" stroke="white" strokeWidth="0.5px" />
                                        </g>
                                        <defs>
                                            <clipPath id="auth-side-panel-grid-clip">
                                                <rect width={161} height={161} fill="white" />
                                            </clipPath>
                                        </defs>
                                    </svg>
                                </div>
                                <div className={`z-10 flex h-[470px] items-center justify-center border border-white/40 bg-white/20 ${GRID_WIDTH}`}>
                                    <div className="max-w-[340px] px-4">
                                        <img
                                            alt="NateUI"
                                            className="mx-auto h-10"
                                            src={`${assetBase}/logos/logo-white-collapsed.svg`}
                                        />
                                        <h2 className="mt-8 text-3xl font-semibold text-white">
                                            Start your journey with us!
                                        </h2>
                                        <p className="mt-4 text-base font-light text-white/80">
                                            Discover the power of our app and unlock a world
                                            of possibilities.
                                        </p>
                                        <Button
                                            className="mt-8 text-foreground dark:border-gray-100 dark:bg-gray-100 dark:text-gray-900 dark:hover:border-gray-200 dark:hover:bg-gray-200"
                                            size="lg"
                                        >
                                            Learn More
                                        </Button>
                                    </div>
                                </div>
                            </div>
                            <div className="flex-1 bg-primary text-white/30 bg-[repeating-linear-gradient(125deg,_transparent,_transparent_6px,_currentColor_6px,_currentColor_7px)]" />
                        </div>
                        <div className={`flex flex-1 divide-x ${DIVIDER_COLOR}`}>
                            <div className="relative flex-1">
                                <div className="absolute -right-1 -top-1 z-20 h-2 w-2 bg-white" />
                            </div>
                            <div className={`relative ${GRID_WIDTH}`}>
                                <div className="absolute left-0 top-0 h-full w-full bg-primary">
                                    <svg
                                        width="100%"
                                        height="100%"
                                        viewBox="0 0 161 161"
                                        fill="none"
                                        xmlns="http://www.w3.org/2000/svg"
                                        className={SVG_OPACITY}
                                        preserveAspectRatio="none"
                                    >
                                        <path d="M50.7645 0.428005V160.572" stroke="white" strokeWidth="0.5px" />
                                        <path d="M80.6943 0.428005V160.572" stroke="white" strokeWidth="0.5px" />
                                        <path d="M110.624 0.386559V160.531" stroke="white" strokeWidth="0.5px" />
                                    </svg>
                                </div>
                            </div>
                            <div className="relative flex-1">
                                <div className="absolute -left-1 -top-1 z-20 h-2 w-2 bg-white" />
                            </div>
                        </div>
                    </div>
                </aside>
            }
        >
            <section aria-labelledby="auth-side-panel-title" className="w-full">
                <header className="mb-8">
                    <h3
                        id="auth-side-panel-title"
                        className="text-2xl font-semibold leading-tight text-foreground"
                    >
                        Create your account
                    </h3>
                    <p className="mt-2 text-muted-foreground">
                        Tell us a bit about yourself to get started.
                    </p>
                </header>

                <SignUpForm
                    fields={[
                        'email',
                        'userName',
                        'password',
                    ]}
                    submitText="Create my account"
                    submittingText="Creating account..."
                />

                <p className="mt-8 text-center text-muted-foreground">
                    Already have an account?{' '}
                    <Link className="font-medium text-primary" href="#log-in">
                        Sign in
                    </Link>
                </p>
            </section>
        </AuthShellSide>
    )
}

Authentication 15

Preview
npx nateui@latest add AuthSideSplit
Dark
import Button from '@/components/ui/Button'
import Link from '@/components/ui/Link'
import Divider from '@/components/composites/Divider'
import AuthShellSplit from '@/components/layouts/AuthShellSplit'
import SignInForm from '@/components/patterns/SignInForm'

const assetBase = 'https://statics.nateui.com/img'

export default function AuthSideSplit() {
    return (
        <AuthShellSplit
            className="h-screen"
            sideContent={
                <aside className="relative hidden flex-col overflow-hidden rounded-card bg-gradient-to-b from-primary/20 via-primary/5 to-background lg:flex">
                    <div className="px-8 pt-12 xl:px-12 xl:pt-16">
                        <h2 className="text-2xl xl:text-3xl leading-tight">
                            Know where every relationship stands.
                        </h2>
                        <p className="mt-2 xl:text-base text-muted-foreground">
                            Connection strength, owner, and open deals on one
                            screen — so a warm account never quietly goes cold.
                        </p>
                    </div>
                    <div className="relative mt-12 min-h-0 flex-1 overflow-hidden mask-b-from-55% xl:mt-16">
                        <div className="absolute left-8 top-0 h-[115%] w-[130%] rounded-[30px] xl:rounded-[40px] bg-inverse/10 p-2 xl:left-12">
                            <img
                                alt=""
                                className="h-full w-full rounded-[24px] object-cover object-left-top"
                                src={`${assetBase}/thumbs/misc/img-30.png`}
                            />
                        </div>
                    </div>
                </aside>
            }
        >
            <section aria-labelledby="auth-side-split-title" className="w-full">
                <div className="mb-4 flex items-center">
                    <img
                        alt=""
                        className="h-9 w-auto dark:hidden"
                        src={`${assetBase}/logos/logo-collapsed.svg`}
                    />
                    <img
                        alt="NateUI"
                        className="hidden h-9 w-auto dark:block"
                        src={`${assetBase}/logos/logo-collapsed-white.svg`}
                    />
                </div>

                <header className="mb-8">
                    <h3
                        id="auth-side-split-title"
                        className="text-2xl font-semibold leading-tight text-foreground"
                    >
                        Welcome back
                    </h3>
                </header>

                <div className="grid grid-cols-2 gap-4">
                    <Button
                        block
                        icon={
                            <img
                                alt=""
                                className="h-5 w-5 object-contain"
                                src={`${assetBase}/thumbs/brands/google.png`}
                            />
                        }
                        type="button"
                        variant="default"
                    >
                        Google
                    </Button>
                    <Button
                        block
                        icon={
                            <svg
                                aria-hidden="true"
                                className="h-5 w-5"
                                fill="currentColor"
                                viewBox="0 0 24 24"
                            >
                                <path d="M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zm3.24-2.939c.84-1.012 1.402-2.42 1.245-3.827-1.207.052-2.665.805-3.532 1.817-.78.896-1.454 2.335-1.271 3.715 1.336.104 2.717-.688 3.558-1.705z" />
                            </svg>
                        }
                        type="button"
                        variant="default"
                    >
                        Apple
                    </Button>
                </div>

                <div className="flex items-center gap-2 py-4">
                    <Divider className="my-0" />
                    <span>or</span>
                    <Divider className="my-0" />
                </div>

                <SignInForm
                    hint={
                        <div className="mt-4 mb-8">
                            <Link
                                className="font-medium text-primary"
                                href="#password-recovery"
                            >
                                Forgot password?
                            </Link>
                        </div>
                    }
                    submitText="Log in"
                    submittingText="Logging in..."
                />

                <p className="mt-8 text-center text-muted-foreground">
                    New here?{' '}
                    <Link href="#sign-up" className="font-medium text-primary">
                        Create an account
                    </Link>
                </p>
            </section>
        </AuthShellSplit>
    )
}