Components
Loading preview...
This design presents a sleek and user-friendly login page. The UI features a contemporary dark mode aesthetic with a deep blue background accented by subtle radial gradients that give depth.
@arunachalam0606
npx shadcn@latest add https://21st.dev/r/arunachalam0606/modern-animated-sign-in'use client';
import { useState, ChangeEvent, FormEvent, ReactNode } from 'react';
import {
Ripple,
AuthTabs,
TechOrbitDisplay,
} from '@/components/blocks/modern-animated-sign-in';
import Image from 'next/image';
type FormData = {
email: string;
password: string;
};
interface OrbitIcon {
component: () => ReactNode;
className: string;
duration?: number;
delay?: number;
radius?: number;
path?: boolean;
reverse?: boolean;
}
const iconsArray: OrbitIcon[] = [
{
component: () => (
<Image
width={100}
height={100}
src='https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/html5/html5-original.svg'
alt='HTML5'
/>
),
className: 'size-[30px] border-none bg-transparent',
duration: 20,
delay: 20,
radius: 100,
path: false,
reverse: false,
},
{
component: () => (
<Image
width={100}
height={100}
src='https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/css3/css3-original.svg'
alt='CSS3'
/>
),
className: 'size-[30px] border-none bg-transparent',
duration: 20,
delay: 10,
radius: 100,
path: false,
reverse: false,
},
{
component: () => (
<Image
width={100}
height={100}
src='https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/typescript/typescript-original.svg'
alt='TypeScript'
/>
),
className: 'size-[50px] border-none bg-transparent',
radius: 210,
duration: 20,
path: false,
reverse: false,
},
{
component: () => (
<Image
width={100}
height={100}
src='https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/javascript/javascript-original.svg'
alt='JavaScript'
/>
),
className: 'size-[50px] border-none bg-transparent',
radius: 210,
duration: 20,
delay: 20,
path: false,
reverse: false,
},
{
component: () => (
<Image
width={100}
height={100}
src='https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/tailwindcss/tailwindcss-original.svg'
alt='TailwindCSS'
/>
),
className: 'size-[30px] border-none bg-transparent',
duration: 20,
delay: 20,
radius: 150,
path: false,
reverse: true,
},
{
component: () => (
<Image
width={100}
height={100}
src='https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/nextjs/nextjs-original.svg'
alt='Nextjs'
/>
),
className: 'size-[30px] border-none bg-transparent',
duration: 20,
delay: 10,
radius: 150,
path: false,
reverse: true,
},
{
component: () => (
<Image
width={100}
height={100}
src='https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/react/react-original.svg'
alt='React'
/>
),
className: 'size-[50px] border-none bg-transparent',
radius: 270,
duration: 20,
path: false,
reverse: true,
},
{
component: () => (
<Image
width={100}
height={100}
src='https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/figma/figma-original.svg'
alt='Figma'
/>
),
className: 'size-[50px] border-none bg-transparent',
radius: 270,
duration: 20,
delay: 60,
path: false,
reverse: true,
},
{
component: () => (
<Image
width={100}
height={100}
src='https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/git/git-original.svg'
alt='Git'
/>
),
className: 'size-[50px] border-none bg-transparent',
radius: 320,
duration: 20,
delay: 20,
path: false,
reverse: false,
},
];
export function Demo() {
const [formData, setFormData] = useState<FormData>({
email: '',
password: '',
});
const goToForgotPassword = (
event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>
) => {
event.preventDefault();
console.log('forgot password');
};
const handleInputChange = (
event: ChangeEvent<HTMLInputElement>,
name: keyof FormData
) => {
const value = event.target.value;
setFormData((prevState) => ({
...prevState,
[name]: value,
}));
};
const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log('Form submitted', formData);
};
const formFields = {
header: 'Welcome back',
subHeader: 'Sign in to your account',
fields: [
{
label: 'Email',
required: true,
type: 'email',
placeholder: 'Enter your email address',
onChange: (event: ChangeEvent<HTMLInputElement>) =>
handleInputChange(event, 'email'),
},
{
label: 'Password',
required: true,
type: 'password',
placeholder: 'Enter your password',
onChange: (event: ChangeEvent<HTMLInputElement>) =>
handleInputChange(event, 'password'),
},
],
submitButton: 'Sign in',
textVariantButton: 'Forgot password?',
};
return (
<section className='flex max-lg:justify-center'>
{/* Left Side */}
<span className='flex flex-col justify-center w-1/2 max-lg:hidden'>
<Ripple mainCircleSize={100} />
<TechOrbitDisplay iconsArray={iconsArray} />
</span>
{/* Right Side */}
<span className='w-1/2 h-[100dvh] flex flex-col justify-center items-center max-lg:w-full max-lg:px-[10%]'>
<AuthTabs
formFields={formFields}
goTo={goToForgotPassword}
handleSubmit={handleSubmit}
/>
</span>
</section>
);
}