Add registration and login pages

Added new pages for user registration and login. Also implemented registration and login forms. Updated dependencies in package.json and modified layout design in header and theme-selector components.
This commit is contained in:
Mathis H (Avnyr) 2024-05-16 08:59:00 +02:00
parent 4559bc1431
commit 43f9d8204c
14 changed files with 1634 additions and 964 deletions

45
.idea/workspace.xml generated
View File

@ -5,12 +5,17 @@
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="42d2b9e8-8d19-46be-8636-69ddba4519e4" name="Changes" comment=""> <list default="true" id="42d2b9e8-8d19-46be-8636-69ddba4519e4" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/src/app/account/login/page.tsx" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/app/account/register/page.tsx" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/components/login-form.tsx" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/components/register-form.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/package.json" afterDir="false" /> <change beforePath="$PROJECT_DIR$/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/package.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pnpm-lock.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/pnpm-lock.yaml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/pnpm-lock.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/pnpm-lock.yaml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/app/globals.css" beforeDir="false" afterPath="$PROJECT_DIR$/src/app/globals.css" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/app/layout.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/app/layout.tsx" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/app/layout.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/app/layout.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/app/page.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/app/page.tsx" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/app/page.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/app/page.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/tailwind.config.ts" beforeDir="false" afterPath="$PROJECT_DIR$/tailwind.config.ts" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/components/header.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/header.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/theme-selector.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/theme-selector.tsx" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -28,6 +33,9 @@
<component name="Git.Settings"> <component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component> </component>
<component name="PackageJsonUpdateNotifier">
<dismissed value="$PROJECT_DIR$/package.json" />
</component>
<component name="ProjectColorInfo">{ <component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 2 &quot;associatedIndex&quot;: 2
}</component> }</component>
@ -36,23 +44,23 @@
<option name="hideEmptyMiddlePackages" value="true" /> <option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" /> <option name="showLibraryContents" value="true" />
</component> </component>
<component name="PropertiesComponent">{ <component name="PropertiesComponent"><![CDATA[{
&quot;keyToString&quot;: { "keyToString": {
&quot;ASKED_ADD_EXTERNAL_FILES&quot;: &quot;true&quot;, "ASKED_ADD_EXTERNAL_FILES": "true",
&quot;ASKED_SHARE_PROJECT_CONFIGURATION_FILES&quot;: &quot;true&quot;, "ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;, "RunOnceActivity.ShowReadmeOnStart": "true",
&quot;last_opened_file_path&quot;: &quot;/home/avnyr/workspace/Simplon/brief-06-front&quot;, "last_opened_file_path": "/home/avnyr/workspace/Simplon/brief-06-front",
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;, "node.js.detected.package.eslint": "true",
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;, "node.js.detected.package.tslint": "true",
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;, "node.js.selected.package.eslint": "(autodetect)",
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;, "node.js.selected.package.tslint": "(autodetect)",
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;, "nodejs_package_manager_path": "npm",
&quot;npm.dev.executor&quot;: &quot;Run&quot;, "npm.dev.executor": "Run",
&quot;settings.editor.selected.configurable&quot;: &quot;preferences.pluginManager&quot;, "settings.editor.selected.configurable": "preferences.pluginManager",
&quot;ts.external.directory.path&quot;: &quot;/home/avnyr/workspace/Simplon/brief-06-front/node_modules/typescript/lib&quot;, "ts.external.directory.path": "/home/avnyr/monoliths/Simplon/brief-06-front/node_modules/typescript/lib",
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot; "vue.rearranger.settings.migration": "true"
} }
}</component> }]]></component>
<component name="RunManager"> <component name="RunManager">
<configuration name="dev" type="js.build_tools.npm" nameIsGenerated="true"> <configuration name="dev" type="js.build_tools.npm" nameIsGenerated="true">
<package-json value="$PROJECT_DIR$/package.json" /> <package-json value="$PROJECT_DIR$/package.json" />
@ -83,6 +91,7 @@
<updated>1715776265663</updated> <updated>1715776265663</updated>
<workItem from="1715776267209" duration="3260000" /> <workItem from="1715776267209" duration="3260000" />
<workItem from="1715781823049" duration="3317000" /> <workItem from="1715781823049" duration="3317000" />
<workItem from="1715794057604" duration="8757000" />
</task> </task>
<servers /> <servers />
</component> </component>

View File

@ -12,9 +12,11 @@
"@fontsource-variable/kode-mono": "^5.0.3", "@fontsource-variable/kode-mono": "^5.0.3",
"@fontsource/ubuntu": "^5.0.13", "@fontsource/ubuntu": "^5.0.13",
"@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-toast": "^1.1.5", "@radix-ui/react-toast": "^1.1.5",
"@radix-ui/react-tooltip": "^1.0.7", "@radix-ui/react-tooltip": "^1.0.7",
"@tailwindcss/forms": "^0.5.7",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"framer-motion": "^11.2.0", "framer-motion": "^11.2.0",

2093
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,12 @@
import React from "react";
import {Button} from "@/components/ui/button";
import {KeyRound, Rss, UserRoundPlus} from "lucide-react";
import {LoginForm} from "@/components/login-form";
export default function LoginPage() {
return (
<main className="flex flex-col justify-evenly items-center antialiased h-full w-full">
<LoginForm/>
</main>
);
}

19
src/app/account/page.tsx Normal file
View File

@ -0,0 +1,19 @@
import React from "react";
import {Button} from "@/components/ui/button";
import {KeyRound, Rss, UserRoundPlus} from "lucide-react";
export default function AccountPage() {
return (
<main className="flex flex-col justify-evenly items-center antialiased h-full w-full">
<section className={"flex flex-col justify-evenly items-center md:h-1/3 mt-4 p-2 w-full h-full gap-1"}>
<h1 className={"text-4xl md:text-6xl font-bold"}>Only<em className={"text-primary opacity-65"}>Devs</em></h1>
<h2 className={"text-xl md:text-3xl text-center mt-1"}>A social network for you the <em className={"text-primary opacity-65"}>nerdy</em> developer !</h2>
<div className={"flex flex-col md:flex-row justify-evenly max-w-64 w-full md:max-w-full mt-2 gap-1"}>
<Button className={"mt-3 md:scale-125 gap-2 bg-purple-600"}><KeyRound />Login</Button>
<Button className={"mt-3 md:scale-125 gap-2 bg-purple-800"}><UserRoundPlus />Register</Button>
<Button className={"mt-3 md:scale-125 gap-2"}><Rss />Go see the posts</Button>
</div>
</section>
</main>
);
}

View File

@ -0,0 +1,11 @@
import React from "react";
import {Button} from "@/components/ui/button";
import {RegisterForm} from "@/components/register-form";
export default function RegisterPage() {
return (
<main className="flex flex-col justify-evenly items-center antialiased h-full w-full">
<RegisterForm/>
</main>
);
}

View File

@ -4,6 +4,8 @@ import "./globals.css";
import {ThemeProvider} from "@/components/theme-provider"; import {ThemeProvider} from "@/components/theme-provider";
import {ToastProvider} from "@/components/ui/toast"; import {ToastProvider} from "@/components/ui/toast";
import Header from "@/components/header"; import Header from "@/components/header";
import {BackgroundBeams} from "@/components/ui/background-beams";
import React from "react";
export const metadata: Metadata = { export const metadata: Metadata = {
@ -18,7 +20,7 @@ export default function RootLayout({
}>) { }>) {
return ( return (
<html lang="en"> <html lang="en">
<body className={"flex flex-col justify-center items-center"}> <body className={"flex flex-col justify-center items-center relative"}>
<ThemeProvider <ThemeProvider
attribute="class" attribute="class"
defaultTheme="system" defaultTheme="system"
@ -29,6 +31,7 @@ export default function RootLayout({
{children} {children}
<ToastProvider/> <ToastProvider/>
</ThemeProvider> </ThemeProvider>
<BackgroundBeams className={"-z-10 w-full h-full fixed"}/>
</body> </body>
</html> </html>
) )

View File

@ -1,22 +1,20 @@
import Image from "next/image";
import {BackgroundBeams} from "@/components/ui/background-beams";
import React from "react"; import React from "react";
import {Button} from "@/components/ui/button"; import {Button} from "@/components/ui/button";
import {KeyRound, Rss, UserRoundPlus} from "lucide-react"; import {KeyRound, Rss, UserRoundPlus} from "lucide-react";
import Link from "next/link";
export default function Home() { export default function Home() {
return ( return (
<main className="flex flex-col justify-center items-center antialiased h-full"> <main className="flex flex-col justify-evenly items-center antialiased h-full w-full">
<section className={"flex flex-col justify-center items-center md:h-1/3 mt-4 p-2 w-full gap-1"}> <section className={"flex flex-col justify-evenly items-center md:h-1/3 mt-4 p-2 w-full h-full gap-1"}>
<h1 className={"text-4xl md:text-6xl font-bold"}>Only<em className={"text-primary"}>Devs</em></h1> <h1 className={"text-4xl md:text-6xl font-bold"}>Only<em className={"text-primary opacity-65"}>Devs</em></h1>
<h2 className={"text-xl md:text-3xl text-center"}>A social network for you the nerdy developer !</h2> <h2 className={"text-xl md:text-3xl text-center mt-1"}>A social network for you the <em className={"text-primary opacity-65"}>nerdy</em> developer !</h2>
<div className={"flex flex-col md:flex-row justify-evenly w-full"}> <div className={"flex flex-col md:flex-row justify-evenly max-w-64 w-full md:max-w-full mt-2 gap-1"}>
<Button className={"mt-3 md:scale-125 gap-2"}><KeyRound />Login</Button> <Button className={"mt-3 md:scale-125 bg-purple-600"} asChild><Link href={"/account/login"} className={"flex flex-row gap-2"}><KeyRound />Login</Link></Button>
<Button className={"mt-3 md:scale-125 gap-2"}><UserRoundPlus />Register</Button> <Button className={"mt-3 md:scale-125 gap-2 bg-purple-800"} asChild><Link href={"/account/register"}><UserRoundPlus />Register</Link></Button>
<Button className={"mt-3 md:scale-125 gap-2"}><Rss />Go see the posts</Button> <Button className={"mt-3 md:scale-125 gap-2"} asChild><Link href={"/threads"}><Rss />Go see the posts</Link></Button>
</div> </div>
</section> </section>
<BackgroundBeams className={"-z-10"}/>
</main> </main>
); );
} }

View File

@ -1,12 +1,13 @@
import React from 'react' import React from 'react'
import {Button} from "@/components/ui/button"; import {Button} from "@/components/ui/button";
import {ThemeSelector} from "@/components/theme-selector"; import {ThemeSelector} from "@/components/theme-selector";
import Link from "next/link";
export const Header = () => { export const Header = () => {
return ( return (
<header className="flex flex-row justify-between items-center p-2 w-full z-50"> <header className="flex flex-row justify-between items-center p-2 w-full z-50">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<h1 className={"text-2xl font-bold"}>Only<em className={"text-primary"}>Devs</em></h1> <Link href={"/"}><h1 className={"text-2xl font-bold"}>Only<em className={"text-primary"}>Devs</em></h1></Link>
</div> </div>
<ThemeSelector/> <ThemeSelector/>
</header> </header>

View File

@ -0,0 +1,99 @@
"use client";
import React from "react";
import {Label} from "@/components/ui/label";
import {Input} from "@/components/ui/input";
import {cn} from "@/lib/utils";
import {User} from "lucide-react";
export function LoginForm() {
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log("Form submitted");
};
return (
<div className="max-w-md w-full mx-auto rounded-none md:rounded-2xl p-4 md:p-8 shadow-input">
<h2 className="font-bold text-xl text-neutral-800 dark:text-neutral-200">
Welcome to OnlyDevs
</h2>
<p className="text-neutral-600 text-sm max-w-sm mt-2 dark:text-neutral-300">
Login to aceternity if you can because we don&apos;t have a login flow
yet
</p>
<form className="my-8" onSubmit={handleSubmit}>
<div className="flex flex-col md:flex-row space-y-2 md:space-y-0 md:space-x-2 mb-4">
<LabelInputContainer>
<Label htmlFor="firstname">First name</Label>
<Input id="firstname" placeholder="John" type="text" />
</LabelInputContainer>
<LabelInputContainer>
<Label htmlFor="lastname">Last name</Label>
<Input id="lastname" placeholder="Doe" type="text" />
</LabelInputContainer>
</div>
<LabelInputContainer className="mb-4">
<Label htmlFor="email">Email Address</Label>
<Input id="email" placeholder="projectmayhem@fc.com" type="email" />
</LabelInputContainer>
<LabelInputContainer className="mb-4">
<Label htmlFor="password">Password</Label>
<Input id="password" placeholder="••••••••" type="password" />
</LabelInputContainer>
<LabelInputContainer className="mb-8">
<Label htmlFor="twitterpassword">Your twitter password</Label>
<Input
id="twitterpassword"
placeholder="••••••••"
type="twitterpassword"
/>
</LabelInputContainer>
<button
className="bg-gradient-to-br relative group/btn from-black dark:from-zinc-900 dark:to-zinc-900 to-neutral-600 block dark:bg-zinc-800 w-full text-white rounded-md h-10 font-medium shadow-[0px_1px_0px_0px_#ffffff40_inset,0px_-1px_0px_0px_#ffffff40_inset] dark:shadow-[0px_1px_0px_0px_var(--zinc-800)_inset,0px_-1px_0px_0px_var(--zinc-800)_inset]"
type="submit"
>
Sign up &rarr;
<BottomGradient />
</button>
<div className="bg-gradient-to-r from-transparent via-neutral-300 dark:via-neutral-700 to-transparent my-8 h-[1px] w-full" />
<div className="flex flex-col space-y-4">
<button
className=" relative group/btn flex space-x-2 items-center justify-start px-4 w-full text-black rounded-md h-10 font-medium shadow-input bg-gray-50 dark:bg-zinc-900 dark:shadow-[0px_0px_1px_1px_var(--neutral-800)]"
type="submit"
>
<User className="h-4 w-4 text-neutral-800 dark:text-neutral-300" />
<span className="text-neutral-700 dark:text-neutral-300 text-sm">
OnlyFans
</span>
<BottomGradient />
</button>
</div>
</form>
</div>
);
}
const BottomGradient = () => {
return (
<>
<span className="group-hover/btn:opacity-100 block transition duration-500 opacity-0 absolute h-px w-full -bottom-px inset-x-0 bg-gradient-to-r from-transparent via-cyan-500 to-transparent" />
<span className="group-hover/btn:opacity-100 blur-sm block transition duration-500 opacity-0 absolute h-px w-1/2 mx-auto -bottom-px inset-x-10 bg-gradient-to-r from-transparent via-indigo-500 to-transparent" />
</>
);
};
const LabelInputContainer = ({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) => {
return (
<div className={cn("flex flex-col space-y-2 w-full", className)}>
{children}
</div>
);
};

View File

@ -0,0 +1,94 @@
"use client";
import React from "react";
import {Label} from "@/components/ui/label";
import {Input} from "@/components/ui/input";
import {cn} from "@/lib/utils";
import {User} from "lucide-react";
export function RegisterForm() {
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log("Form submitted");
};
return (
<div className="max-w-md w-full mx-auto rounded-none md:rounded-2xl p-4 md:p-8 shadow-input">
<h2 className="font-bold text-xl text-neutral-800 dark:text-neutral-200">
Create an account
</h2>
<p className="text-neutral-600 text-sm max-w-sm mt-2 dark:text-neutral-300">
By creating an account you can discuss on our platform.
</p>
<form className="my-8" onSubmit={handleSubmit}>
<div className="flex flex-col md:flex-row space-y-2 md:space-y-0 md:space-x-2 mb-4">
<LabelInputContainer>
<Label htmlFor="firstname">First name</Label>
<Input id="firstname" placeholder="John" type="text"/>
</LabelInputContainer>
<LabelInputContainer>
<Label htmlFor="lastname">Last name</Label>
<Input id="lastname" placeholder="Doe" type="text"/>
</LabelInputContainer>
</div>
<LabelInputContainer className="mb-4">
<Label htmlFor="email">Email Address</Label>
<Input id="email" placeholder="john.doe@foo.bar" type="email"/>
</LabelInputContainer>
<div
className="bg-gradient-to-r from-transparent via-neutral-300 dark:via-neutral-700 to-transparent my-8 h-[1px] w-full"/>
<LabelInputContainer className="mb-4">
<Label htmlFor="username">Username</Label>
<Input id="username" placeholder="john.doe68" type="text"/>
</LabelInputContainer>
<LabelInputContainer className="mb-4">
<Label htmlFor="displayName">Displayname</Label>
<Input id="displayName" placeholder="Johny" type="text"/>
</LabelInputContainer>
<LabelInputContainer className="mb-4">
<Label htmlFor="password">Password</Label>
<Input id="password" placeholder="••••••••" type="password"/>
</LabelInputContainer>
<LabelInputContainer className="mb-8">
<Label htmlFor="re-password">Re-type password</Label>
<Input
id="re-password"
placeholder="••••••••"
type="password"
/>
</LabelInputContainer>
<button
className="bg-gradient-to-br relative group/btn from-black dark:from-zinc-900 dark:to-zinc-900 to-neutral-600 block dark:bg-zinc-800 w-full text-white rounded-md h-10 font-medium shadow-[0px_1px_0px_0px_#ffffff40_inset,0px_-1px_0px_0px_#ffffff40_inset] dark:shadow-[0px_1px_0px_0px_var(--zinc-800)_inset,0px_-1px_0px_0px_var(--zinc-800)_inset]"
type="submit"
>
Register &rarr;
<BottomGradient/>
</button>
</form>
</div>
);
}
const BottomGradient = () => {
return (
<>
<span
className="group-hover/btn:opacity-100 block transition duration-500 opacity-0 absolute h-px w-full -bottom-px inset-x-0 bg-gradient-to-r from-transparent via-cyan-500 to-transparent" />
<span className="group-hover/btn:opacity-100 blur-sm block transition duration-500 opacity-0 absolute h-px w-1/2 mx-auto -bottom-px inset-x-10 bg-gradient-to-r from-transparent via-indigo-500 to-transparent" />
</>
);
};
const LabelInputContainer = ({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) => {
return (
<div className={cn("flex flex-col space-y-2 w-full", className)}>
{children}
</div>
);
};

View File

@ -20,14 +20,14 @@ export function ThemeSelector() {
//TODO i18n //TODO i18n
return ( return (
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild className={""}>
<Button variant="outline" size="icon"> <Button variant="outline" size="icon">
<Sun className="h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:-rotate-90 dark:scale-100 text-primary animate-in" /> <Sun className="h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:-rotate-90 dark:scale-100 text-primary animate-in" />
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:rotate-0 dark:scale-0 text-primary animate-in" /> <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:rotate-0 dark:scale-0 text-primary animate-in" />
<span className="sr-only">Toggle theme</span> <span className="sr-only">Toggle theme</span>
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent className="flex flex-col m-2"> <DropdownMenuContent className="flex flex-col m-2 z-50">
<DropdownMenuLabel>Theme de couleur</DropdownMenuLabel> <DropdownMenuLabel>Theme de couleur</DropdownMenuLabel>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuGroup> <DropdownMenuGroup>

View File

@ -0,0 +1,25 @@
import * as React from "react"
import { cn } from "@/lib/utils"
export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
)
}
)
Input.displayName = "Input"
export { Input }

View File

@ -0,0 +1,26 @@
"use client"
import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const labelVariants = cva(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
)
const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
VariantProps<typeof labelVariants>
>(({ className, ...props }, ref) => (
<LabelPrimitive.Root
ref={ref}
className={cn(labelVariants(), className)}
{...props}
/>
))
Label.displayName = LabelPrimitive.Root.displayName
export { Label }