From 67fe4074404f0e4cd9ee3b7456c718371a1bb3a9 Mon Sep 17 00:00:00 2001 From: Harsh Tiwari Date: Wed, 2 Oct 2024 20:02:08 +0530 Subject: [PATCH] "Authentication UI" --- .vscode/settings.json | 3 + bun.lockb | Bin 146313 -> 151465 bytes components.json | 20 ++++ package.json | 11 +- src/app/globals.css | 83 +++++++++++++-- src/app/page.tsx | 100 +------------------ src/components/ui/button.tsx | 56 +++++++++++ src/components/ui/card.tsx | 79 +++++++++++++++ src/components/ui/input.tsx | 25 +++++ src/components/ui/separator.tsx | 31 ++++++ src/features/auth/components/auth-screen.tsx | 22 ++++ src/features/auth/components/sign-in.tsx | 85 ++++++++++++++++ src/features/auth/components/sign-up.tsx | 85 ++++++++++++++++ src/features/auth/types.ts | 1 + src/lib/utils.ts | 6 ++ tailwind.config.ts | 51 +++++++++- 16 files changed, 547 insertions(+), 111 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 components.json create mode 100644 src/components/ui/button.tsx create mode 100644 src/components/ui/card.tsx create mode 100644 src/components/ui/input.tsx create mode 100644 src/components/ui/separator.tsx create mode 100644 src/features/auth/components/auth-screen.tsx create mode 100644 src/features/auth/components/sign-in.tsx create mode 100644 src/features/auth/components/sign-up.tsx create mode 100644 src/features/auth/types.ts create mode 100644 src/lib/utils.ts diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..3062a39 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.fontSize": 16 +} diff --git a/bun.lockb b/bun.lockb index 1ab55664cff0f05b3d057eb7f7f13800f142784b..4b0b4995ef125f470f4c4c06a527da8fece4b948 100755 GIT binary patch delta 32437 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 a`d0JX^zv8Qmz9m&T6*zKSKa!CZvO|vA~y5@ diff --git a/components.json b/components.json new file mode 100644 index 0000000..2009941 --- /dev/null +++ b/components.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "src/app/globals.css", + "baseColor": "slate", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + } +} \ No newline at end of file diff --git a/package.json b/package.json index 02d9c20..f12ab0b 100644 --- a/package.json +++ b/package.json @@ -9,9 +9,18 @@ "lint": "next lint" }, "dependencies": { + "@radix-ui/react-icons": "^1.3.0", + "@radix-ui/react-separator": "^1.1.0", + "@radix-ui/react-slot": "^1.1.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "lucide-react": "^0.447.0", + "next": "14.2.14", "react": "^18", "react-dom": "^18", - "next": "14.2.14" + "react-icons": "^5.3.0", + "tailwind-merge": "^2.5.2", + "tailwindcss-animate": "^1.0.7" }, "devDependencies": { "typescript": "^5", diff --git a/src/app/globals.css b/src/app/globals.css index 13d40b8..9b5e390 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -2,21 +2,21 @@ @tailwind components; @tailwind utilities; +html, +body, +#__next, :root { - --background: #ffffff; - --foreground: #171717; + height: 100%; } -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } +body { + @apply bg-background text-foreground; } +.dark body { + @apply bg-background text-foreground; +} body { - color: var(--foreground); - background: var(--background); font-family: Arial, Helvetica, sans-serif; } @@ -25,3 +25,68 @@ body { text-wrap: balance; } } + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 222.2 84% 4.9%; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + --radius: 0.5rem; + } + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 212.7 26.8% 83.9%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/src/app/page.tsx b/src/app/page.tsx index 6fe62d1..69cd5cc 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,101 +1,5 @@ -import Image from "next/image"; +import AuthScreen from "@/features/auth/components/auth-screen"; export default function Home() { - return ( - - ); + return ; } diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx new file mode 100644 index 0000000..0ba4277 --- /dev/null +++ b/src/components/ui/button.tsx @@ -0,0 +1,56 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const buttonVariants = cva( + "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: + "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button" + return ( + + ) + } +) +Button.displayName = "Button" + +export { Button, buttonVariants } diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx new file mode 100644 index 0000000..afa13ec --- /dev/null +++ b/src/components/ui/card.tsx @@ -0,0 +1,79 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +Card.displayName = "Card" + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardHeader.displayName = "CardHeader" + +const CardTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardTitle.displayName = "CardTitle" + +const CardDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardDescription.displayName = "CardDescription" + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardContent.displayName = "CardContent" + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardFooter.displayName = "CardFooter" + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx new file mode 100644 index 0000000..a921025 --- /dev/null +++ b/src/components/ui/input.tsx @@ -0,0 +1,25 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +export interface InputProps + extends React.InputHTMLAttributes {} + +const Input = React.forwardRef( + ({ className, type, ...props }, ref) => { + return ( + + ) + } +) +Input.displayName = "Input" + +export { Input } diff --git a/src/components/ui/separator.tsx b/src/components/ui/separator.tsx new file mode 100644 index 0000000..12d81c4 --- /dev/null +++ b/src/components/ui/separator.tsx @@ -0,0 +1,31 @@ +"use client" + +import * as React from "react" +import * as SeparatorPrimitive from "@radix-ui/react-separator" + +import { cn } from "@/lib/utils" + +const Separator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>( + ( + { className, orientation = "horizontal", decorative = true, ...props }, + ref + ) => ( + + ) +) +Separator.displayName = SeparatorPrimitive.Root.displayName + +export { Separator } diff --git a/src/features/auth/components/auth-screen.tsx b/src/features/auth/components/auth-screen.tsx new file mode 100644 index 0000000..dbc94b1 --- /dev/null +++ b/src/features/auth/components/auth-screen.tsx @@ -0,0 +1,22 @@ +"use client"; + +import { useState } from "react"; +import { SignInFlow } from "../types"; +import SignInCard from "./sign-in"; +import SignUpCard from "./sign-up"; + +export default function AuthScreen() { + const [state, setState] = useState("signIn"); + + return ( +
+
+ {state == "signIn" ? ( + + ) : ( + + )} +
+
+ ); +} diff --git a/src/features/auth/components/sign-in.tsx b/src/features/auth/components/sign-in.tsx new file mode 100644 index 0000000..f811eaf --- /dev/null +++ b/src/features/auth/components/sign-in.tsx @@ -0,0 +1,85 @@ +import { FcGoogle } from "react-icons/fc"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { Separator } from "@/components/ui/separator"; +import { FaGithub } from "react-icons/fa"; +import { SignInFlow } from "../types"; + +interface SignInCardProps { + setState: (state: SignInFlow) => void; +} + +export default function SignInCard({ setState }: SignInCardProps) { + return ( + <> + + + Log In to Continue + Use your email or github account + + +
+ {}} + type="email" + placeholder="Email" + required={true} + /> + {}} + type="password" + placeholder="Password" + required={true} + /> + +
+ +
+ + +
+

+ Don't have an account?{" "} + setState("signUp")} + > + Sign Up + +

+
+
+ + ); +} diff --git a/src/features/auth/components/sign-up.tsx b/src/features/auth/components/sign-up.tsx new file mode 100644 index 0000000..a4fd11f --- /dev/null +++ b/src/features/auth/components/sign-up.tsx @@ -0,0 +1,85 @@ +import { FcGoogle } from "react-icons/fc"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { Separator } from "@/components/ui/separator"; +import { FaGithub } from "react-icons/fa"; +import { SignInFlow } from "../types"; + +interface SignUpCardProps { + setState: (state: SignInFlow) => void; +} + +export default function SignUpCard({ setState }: SignUpCardProps) { + return ( + <> + + + Sign Up to Continue + Use your email or github account + + +
+ {}} + type="email" + placeholder="Email" + required={true} + /> + {}} + type="password" + placeholder="Password" + required={true} + /> + +
+ +
+ + +
+

+ Already have an account?{" "} + setState("signIn")} + > + Sign In + +

+
+
+ + ); +} diff --git a/src/features/auth/types.ts b/src/features/auth/types.ts new file mode 100644 index 0000000..8dba38d --- /dev/null +++ b/src/features/auth/types.ts @@ -0,0 +1 @@ +export type SignInFlow = "signIn" | "signUp"; diff --git a/src/lib/utils.ts b/src/lib/utils.ts new file mode 100644 index 0000000..bd0c391 --- /dev/null +++ b/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/tailwind.config.ts b/tailwind.config.ts index 021c393..017dcef 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,19 +1,64 @@ import type { Config } from "tailwindcss"; const config: Config = { + darkMode: ["class"], content: [ "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", "./src/components/**/*.{js,ts,jsx,tsx,mdx}", "./src/app/**/*.{js,ts,jsx,tsx,mdx}", + "./src/features/**/*.{js,ts,jsx,tsx,mdx }", ], theme: { extend: { colors: { - background: "var(--background)", - foreground: "var(--foreground)", + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + chart: { + "1": "hsl(var(--chart-1))", + "2": "hsl(var(--chart-2))", + "3": "hsl(var(--chart-3))", + "4": "hsl(var(--chart-4))", + "5": "hsl(var(--chart-5))", + }, + }, + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", }, }, }, - plugins: [], + plugins: [require("tailwindcss-animate")], }; export default config;