Skip to content

Commit

Permalink
feat: implement PLP made by v0
Browse files Browse the repository at this point in the history
  • Loading branch information
bmstefanski committed Jan 19, 2024
1 parent 54ff034 commit 7941742
Show file tree
Hide file tree
Showing 11 changed files with 657 additions and 1 deletion.
5 changes: 5 additions & 0 deletions apps/web/app/search/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { SearchView } from "views/Search/SearchView"

export default function SearchPage() {
return <SearchView />
}
159 changes: 159 additions & 0 deletions apps/web/components/search-view.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/**
* This code was generated by v0 by Vercel.
* @see https://v0.dev/t/W1VkExg7Hvk
*/
import { AccordionTrigger, AccordionContent, AccordionItem, Accordion } from "components/ui/Accordion"
import { Checkbox } from "components/ui/Checkbox"
import { Label } from "components/ui/Label"
import { Button } from "components/ui/Button"
import { DropdownMenuTrigger, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuItem, DropdownMenuContent, DropdownMenu } from "components/ui/DropdownMenu"
import Link from "next/link"

export function SearchView() {
return (
<div className="container mx-auto px-4 md:px-6 lg:px-8 py-6">
<div className="grid md:grid-cols-[240px_1fr] gap-6">
<div>
<h2 className="text-lg font-semibold mb-4">Filters</h2>
<Accordion className="w-full" collapsible type="single">
<AccordionItem value="category">
<AccordionTrigger className="text-base">Category</AccordionTrigger>
<AccordionContent>
<div className="grid gap-2">
<Label className="flex items-center gap-2 font-normal">
<Checkbox id="category-clothing" />
Clothing{"\n "}
</Label>
<Label className="flex items-center gap-2 font-normal">
<Checkbox id="category-electronics" />
Electronics{"\n "}
</Label>
<Label className="flex items-center gap-2 font-normal">
<Checkbox id="category-home" />
Home & Garden{"\n "}
</Label>
</div>
</AccordionContent>
</AccordionItem>
<AccordionItem value="price">
<AccordionTrigger className="text-base">Price Range</AccordionTrigger>
<AccordionContent>
<div className="grid gap-2">
<Label className="flex items-center gap-2 font-normal">
<Checkbox id="price-under50" />
Under $50{"\n "}
</Label>
<Label className="flex items-center gap-2 font-normal">
<Checkbox id="price-50to100" />
$50 to $100{"\n "}
</Label>
<Label className="flex items-center gap-2 font-normal">
<Checkbox id="price-100to200" />
$100 to $200{"\n "}
</Label>
<Label className="flex items-center gap-2 font-normal">
<Checkbox id="price-over200" />
Over $200{"\n "}
</Label>
</div>
</AccordionContent>
</AccordionItem>
<AccordionItem value="rating">
<AccordionTrigger className="text-base">Rating</AccordionTrigger>
<AccordionContent>
<div className="grid gap-2">
<Label className="flex items-center gap-2 font-normal">
<Checkbox id="rating-5stars" />
5 Stars{"\n "}
</Label>
<Label className="flex items-center gap-2 font-normal">
<Checkbox id="rating-4stars" />
4 Stars & Up{"\n "}
</Label>
<Label className="flex items-center gap-2 font-normal">
<Checkbox id="rating-3stars" />
3 Stars & Up{"\n "}
</Label>
<Label className="flex items-center gap-2 font-normal">
<Checkbox id="rating-2stars" />
2 Stars & Up{"\n "}
</Label>
</div>
</AccordionContent>
</AccordionItem>
</Accordion>
</div>
<div>
<div className="flex items-center justify-between mb-6">
<h1 className="text-2xl font-semibold">Products</h1>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button size="sm" variant="outline">
<ArrowUpDownIcon className="w-4 h-4 mr-2" />
Sort by
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Sort by</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem>Price: Low to High</DropdownMenuItem>
<DropdownMenuItem>Price: High to Low</DropdownMenuItem>
<DropdownMenuItem>Popularity</DropdownMenuItem>
<DropdownMenuItem>Newest</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
<div className="relative group overflow-hidden rounded-lg">
<Link className="absolute inset-0 z-10" href="#">
<span className="sr-only">View</span>
</Link>
<img
alt="Product 1"
className="object-cover w-full h-60"
height={300}
src="/placeholder.svg"
style={{
aspectRatio: "400/300",
objectFit: "cover",
}}
width={400}
/>
<div className="bg-white p-4 dark:bg-gray-950">
<h3 className="font-semibold text-lg md:text-xl">Stylish Sunglasses</h3>
<p className="text-sm text-gray-500 dark:text-gray-400">UV protection</p>
<h4 className="font-semibold text-base md:text-lg">$29.99</h4>
<Button className="mt-2" size="sm">
Add to Cart
</Button>
</div>
</div>
</div>
</div>
</div>
</div>
)
}


function ArrowUpDownIcon(props) {
return (
<svg
{...props}
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="m21 16-4 4-4-4" />
<path d="M17 20V4" />
<path d="m3 8 4-4 4 4" />
<path d="M7 4v16" />
</svg>
)
}
53 changes: 53 additions & 0 deletions apps/web/components/ui/Accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"use client"

import * as React from "react"
import * as AccordionPrimitive from "@radix-ui/react-accordion"
import { ChevronDown } from "lucide-react"
import { cn } from "utils/cn"

const Accordion = AccordionPrimitive.Root

const AccordionItem = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
>(({ className, ...props }, ref) => (
<AccordionPrimitive.Item ref={ref} className={cn("border-b", className)} {...props} />
))
AccordionItem.displayName = "AccordionItem"

const AccordionTrigger = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
ref={ref}
className={cn(
"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
className
)}
{...props}
>
{children}
<ChevronDown className="h-4 w-4 shrink-0 transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
))
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName

const AccordionContent = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Content
ref={ref}
className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm transition-all"
{...props}
>
<div className={cn("pb-4 pt-0", className)}>{children}</div>
</AccordionPrimitive.Content>
))

AccordionContent.displayName = AccordionPrimitive.Content.displayName

export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
46 changes: 46 additions & 0 deletions apps/web/components/ui/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "utils/cn"

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<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />
}
)
Button.displayName = "Button"

export { Button, buttonVariants }
27 changes: 27 additions & 0 deletions apps/web/components/ui/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"use client"

import * as React from "react"
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
import { Check } from "lucide-react"
import { cn } from "utils/cn"

const Checkbox = React.forwardRef<
React.ElementRef<typeof CheckboxPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
>(({ className, ...props }, ref) => (
<CheckboxPrimitive.Root
ref={ref}
className={cn(
"border-primary ring-offset-background focus-visible:ring-ring data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground peer h-4 w-4 shrink-0 rounded-sm border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}
>
<CheckboxPrimitive.Indicator className={cn("flex items-center justify-center text-current")}>
<Check className="h-4 w-4" />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
))
Checkbox.displayName = CheckboxPrimitive.Root.displayName

export { Checkbox }
Loading

0 comments on commit 7941742

Please sign in to comment.