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 1ab5566..4b0b499 100755 Binary files a/bun.lockb and b/bun.lockb differ 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 ( -
-
- Next.js logo -
    -
  1. - Get started by editing{" "} - - src/app/page.tsx - - . -
  2. -
  3. Save and see your changes instantly.
  4. -
- -
- - Vercel logomark - Deploy now - - - Read our docs - -
-
- -
- ); + 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;