diff --git a/components.json b/components.json new file mode 100644 index 0000000..ffe928f --- /dev/null +++ b/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} \ No newline at end of file diff --git a/package.json b/package.json index c3719af..328a83f 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,9 @@ "lint": "next lint" }, "dependencies": { + "@radix-ui/react-dialog": "^1.1.14", + "@radix-ui/react-slot": "^1.2.3", + "clsx": "^2.1.1", "@radix-ui/react-avatar": "^1.1.10", "@radix-ui/react-separator": "^1.1.7", "@starknet-react/chains": "^3.1.3", @@ -32,6 +35,7 @@ "eslint": "^9", "eslint-config-next": "15.3.1", "tailwindcss": "^4", + "tw-animate-css": "^1.3.4", "typescript": "^5" } } diff --git a/public/X.svg b/public/X.svg new file mode 100644 index 0000000..b2f8795 --- /dev/null +++ b/public/X.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/app/playerselection/selection.tsx b/src/app/playerselection/selection.tsx new file mode 100644 index 0000000..5af55a5 --- /dev/null +++ b/src/app/playerselection/selection.tsx @@ -0,0 +1,111 @@ +"use client" + +import { useState } from "react" +import { Button } from "../../components/ui/button" +import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog" +import { Check } from "lucide-react" +import Image from "next/image" + +const colors = [ + { id: "orange", value: "#FF8C42", name: "Orange" }, + { id: "cyan", value: "#00D4FF", name: "Cyan" }, + { id: "purple", value: "#A855F7", name: "Purple" }, + { id: "teal", value: "#0F766E", name: "Teal" }, + { id: "red", value: "#EF4444", name: "Red" }, + { id: "blue", value: "#3B82F6", name: "Blue" }, + { id: "yellow", value: "#EAB308", name: "Yellow" }, + { id: "pink", value: "#EC4899", name: "Pink" }, + { id: "lime", value: "#84CC16", name: "Lime" }, + { id: "white", value: "#FFFFFF", name: "White" }, + { id: "brown", value: "#92400E", name: "Brown" }, + { id: "maroon", value: "#B91C1C", name: "Maroon" }, +] + +export default function ColorSelection() { + const [selectedColor, setSelectedColor] = useState("yellow") + const [takenColors] = useState(["blue", "lime", "pink"]) // Simulated taken colors + const [showConflictDialog, setShowConflictDialog] = useState(false) + const [, setAttemptedColor] = useState("") + + const handleColorSelect = (colorId: string) => { + if (takenColors.includes(colorId)) { + setAttemptedColor(colorId) + setShowConflictDialog(true) + return + } + setSelectedColor(colorId) + } + + const handleCloseDialog = () => { + setShowConflictDialog(false) + setAttemptedColor("") + } + + const getColorStatus = (colorId: string) => { + if (selectedColor === colorId) return "selected" + if (takenColors.includes(colorId)) return "taken" + return "available" + } + + return ( +
+
+

Select your appearance

+ +
+ {colors.map((color) => { + const status = getColorStatus(color.id) + + return ( + + ) + })} +
+ + +
+ + + + + Oops! + + This appearance has been selected by another player. Choose another appearance. + + +
+ +
+
+
+
+ ) +} diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx new file mode 100644 index 0000000..a2df8dc --- /dev/null +++ b/src/components/ui/button.tsx @@ -0,0 +1,59 @@ +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 gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", + destructive: + "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50", + secondary: + "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80", + ghost: + "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2 has-[>svg]:px-3", + sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", + lg: "h-10 rounded-md px-6 has-[>svg]:px-4", + icon: "size-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +function Button({ + className, + variant, + size, + asChild = false, + ...props +}: React.ComponentProps<"button"> & + VariantProps & { + asChild?: boolean + }) { + const Comp = asChild ? Slot : "button" + + return ( + + ) +} + +export { Button, buttonVariants } diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx new file mode 100644 index 0000000..d9ccec9 --- /dev/null +++ b/src/components/ui/dialog.tsx @@ -0,0 +1,143 @@ +"use client" + +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { XIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Dialog({ + ...props +}: React.ComponentProps) { + return +} + +function DialogTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function DialogPortal({ + ...props +}: React.ComponentProps) { + return +} + +function DialogClose({ + ...props +}: React.ComponentProps) { + return +} + +function DialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DialogContent({ + className, + children, + showCloseButton = true, + ...props +}: React.ComponentProps & { + showCloseButton?: boolean +}) { + return ( + + + + {children} + {showCloseButton && ( + + + Close + + )} + + + ) +} + +function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DialogFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, + DialogTitle, + DialogTrigger, +} 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)) +}