Initialized repository for project Paper presents recreation

Co-authored-by: Jeff Emmett <46964190+Jeff-Emmett@users.noreply.github.com>
This commit is contained in:
v0 2025-10-12 01:06:38 +00:00
commit c2051ce9f2
131 changed files with 5892 additions and 0 deletions

27
.gitignore vendored Normal file
View File

@ -0,0 +1,27 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
# next.js
/.next/
/out/
# production
/build
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

30
README.md Normal file
View File

@ -0,0 +1,30 @@
# Paper presents recreation
*Automatically synced with your [v0.app](https://v0.app) deployments*
[![Deployed on Vercel](https://img.shields.io/badge/Deployed%20on-Vercel-black?style=for-the-badge&logo=vercel)](https://vercel.com/jeff-emmetts-projects/v0-paper-presents-recreation)
[![Built with v0](https://img.shields.io/badge/Built%20with-v0.app-black?style=for-the-badge)](https://v0.app/chat/projects/r4IOtZAcYAn)
## Overview
This repository will stay in sync with your deployed chats on [v0.app](https://v0.app).
Any changes you make to your deployed app will be automatically pushed to this repository from [v0.app](https://v0.app).
## Deployment
Your project is live at:
**[https://vercel.com/jeff-emmetts-projects/v0-paper-presents-recreation](https://vercel.com/jeff-emmetts-projects/v0-paper-presents-recreation)**
## Build your app
Continue building your app on:
**[https://v0.app/chat/projects/r4IOtZAcYAn](https://v0.app/chat/projects/r4IOtZAcYAn)**
## How It Works
1. Create and modify your project using [v0.app](https://v0.app)
2. Deploy your chats from the v0 interface
3. Changes are automatically pushed to this repository
4. Vercel deploys the latest version from this repository

126
app/card/[id]/page.tsx Normal file
View File

@ -0,0 +1,126 @@
import { notFound } from "next/navigation"
import Image from "next/image"
import Link from "next/link"
import { cards } from "@/data/cards"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { ChevronRight } from "lucide-react"
export function generateStaticParams() {
return cards.map((card) => ({
id: card.id,
}))
}
export default function CardDetailPage({
params,
}: {
params: { id: string }
}) {
const card = cards.find((c) => c.id === params.id)
if (!card) {
notFound()
}
const categoryName = card.category.charAt(0).toUpperCase() + card.category.slice(1)
return (
<div className="min-h-screen bg-background">
<div className="container mx-auto px-4 py-8">
{/* Breadcrumb */}
<nav className="flex items-center gap-2 text-sm text-muted-foreground mb-8">
<Link href="/" className="hover:text-primary transition-colors">
Home
</Link>
<ChevronRight className="h-4 w-4" />
<Link href={`/category/${card.category}`} className="hover:text-primary transition-colors">
{categoryName}
</Link>
<ChevronRight className="h-4 w-4" />
<span className="text-foreground">{card.name}</span>
</nav>
<div className="grid md:grid-cols-2 gap-12">
{/* Product Image */}
<div className="space-y-4">
<div className="relative aspect-square bg-card rounded-lg overflow-hidden border">
<Image
src={card.image || "/placeholder.svg"}
alt={card.name}
fill
className="object-contain p-8"
priority
/>
<div className="absolute top-4 right-4 bg-primary text-primary-foreground px-4 py-2 rounded-md font-semibold">
${card.price.toFixed(2)}
</div>
</div>
</div>
{/* Product Details */}
<div className="space-y-6">
<div>
<h1 className="text-4xl font-bold text-foreground mb-2">{card.name}</h1>
<p className="text-2xl font-semibold text-primary">${card.price.toFixed(2)}</p>
</div>
{/* Product Information */}
<div className="space-y-3 text-muted-foreground">
<p>
<span className="font-semibold text-foreground">Order Code:</span> {card.orderCode}
</p>
{card.description && (
<p>
<span className="font-semibold text-foreground">Details:</span> {card.description}
</p>
)}
<p>
<span className="font-semibold text-foreground">Dimensions:</span> 12 cm × 12 cm
</p>
<p>
<span className="font-semibold text-foreground">Weight:</span> 25 grams
</p>
</div>
{/* Color Selection */}
<div className="space-y-2">
<Label htmlFor="color">Available Colors:</Label>
<Select defaultValue="red">
<SelectTrigger id="color" className="w-full">
<SelectValue placeholder="Select a color" />
</SelectTrigger>
<SelectContent>
<SelectItem value="red">Red</SelectItem>
<SelectItem value="green">Green</SelectItem>
<SelectItem value="blue">Blue</SelectItem>
<SelectItem value="brown">Brown</SelectItem>
</SelectContent>
</Select>
</div>
{/* Quantity Selection */}
<div className="space-y-2">
<Label htmlFor="quantity">Quantity:</Label>
<Input id="quantity" type="number" min="1" defaultValue="1" className="w-24" />
</div>
{/* Add to Cart Button */}
<Button size="lg" className="w-full">
Add To Cart
</Button>
{/* Additional Info */}
<div className="border-t pt-6 space-y-2 text-sm text-muted-foreground">
<p>All cards are handcrafted 3D pop-up greeting cards made with premium materials.</p>
<p>Each card comes with a matching envelope.</p>
<p>Satisfaction Guaranteed - Quality you can trust.</p>
</div>
</div>
</div>
</div>
</div>
)
}

View File

@ -0,0 +1,88 @@
import { PageHero } from "@/components/page-hero"
import { Card, CardContent } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { getCardsByCategory, getCategoryBySlug, categories } from "@/data/cards"
import { notFound } from "next/navigation"
import Link from "next/link"
export function generateStaticParams() {
return categories.map((category) => ({
slug: category.slug,
}))
}
export default function CategoryPage({ params }: { params: { slug: string } }) {
const category = getCategoryBySlug(params.slug)
if (!category) {
notFound()
}
const categoryCards = getCardsByCategory(params.slug)
return (
<>
<PageHero
title={category.name}
breadcrumbs={[
{ label: "Home", href: "/" },
{ label: "Our Cards", href: "/our-cards" },
]}
/>
<main className="flex-1">
<section className="py-16">
<div className="container mx-auto px-4">
<div className="text-center mb-12">
<p className="text-lg text-muted-foreground max-w-3xl mx-auto">{category.description}</p>
<p className="text-sm text-muted-foreground mt-4">
{categoryCards.length} {categoryCards.length === 1 ? "design" : "designs"} available
</p>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
{categoryCards.map((card) => (
<Link key={card.id} href={`/card/${card.id}`}>
<Card className="h-full hover:shadow-lg transition-shadow group cursor-pointer">
<CardContent className="p-0">
<div className="aspect-[3/4] relative overflow-hidden rounded-t-lg bg-muted">
<img
src={card.image || "/placeholder.svg"}
alt={card.name}
className="object-cover w-full h-full group-hover:scale-105 transition-transform duration-300"
/>
</div>
<div className="p-4">
<div className="flex items-start justify-between gap-2 mb-2">
<h3 className="text-lg font-semibold leading-tight">{card.name}</h3>
{card.price > 0 ? (
<Badge variant="secondary" className="shrink-0">
${card.price.toFixed(2)}
</Badge>
) : (
<Badge variant="outline" className="shrink-0">
Inquire
</Badge>
)}
</div>
<p className="text-sm text-muted-foreground mb-2">Order Code: {card.orderCode}</p>
{card.description && (
<p className="text-xs text-muted-foreground mt-2 italic">{card.description}</p>
)}
{card.variants && card.variants.length > 0 && (
<p className="text-xs text-muted-foreground mt-2">
Also available: {card.variants.join(", ")}
</p>
)}
</div>
</CardContent>
</Card>
</Link>
))}
</div>
</div>
</section>
</main>
</>
)
}

150
app/custom-cards/page.tsx Normal file
View File

@ -0,0 +1,150 @@
import { PageHero } from "@/components/page-hero"
import { Button } from "@/components/ui/button"
import { Card, CardContent } from "@/components/ui/card"
import Link from "next/link"
import { Palette, MessageSquare, CheckCircle, Users } from "lucide-react"
export default function CustomCardsPage() {
const features = [
{
icon: Palette,
title: "Custom Design",
description: "Our talented artists will work with you to create the perfect design",
},
{
icon: MessageSquare,
title: "Your Message",
description: "Choose your font and style for a personalized message",
},
{
icon: CheckCircle,
title: "Digital Proof",
description: "Review and approve before we send to manufacture",
},
{
icon: Users,
title: "Bulk Orders",
description: "Wholesale discounts available for orders of 100+ cards",
},
]
return (
<>
<PageHero title="Custom Cards" breadcrumbs={[{ label: "Home", href: "/" }]} />
<main className="flex-1">
<section className="py-16">
<div className="container mx-auto px-4 max-w-4xl">
<div className="prose prose-lg max-w-none">
<p className="text-lg leading-relaxed mb-6">
If you are interested in customizing any of our cards for your personal events, our talented artists are
happy to take on any challenge.
</p>
<p className="text-lg leading-relaxed mb-6">
Whether you want a card for that special someone or a personalized invitation to your birthday, baby
shower, graduation ceremony, or any other occasion to which you might invite your friends and family, we
can accommodate any of your needs!
</p>
<p className="text-lg leading-relaxed mb-6">
Our design staff will work with you to provide your customized message in a font and style of your
choosing, which will be confirmed by digital proof before being sent to manufacture.
</p>
<p className="text-lg leading-relaxed mb-8">
Due to set up and design costs, minimum orders of 50 cards must be placed for custom orders or
additional design fees apply. Wholesale discounts apply on orders of 100 cards or more, ask for more
details!
</p>
<div className="text-center">
<Button size="lg" asChild>
<Link href="/contact">Ask Us</Link>
</Button>
</div>
</div>
</div>
</section>
{/* Features Grid */}
<section className="py-16 bg-muted">
<div className="container mx-auto px-4">
<h3 className="text-3xl font-bold text-center mb-12">How Custom Cards Work</h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
{features.map((feature) => (
<Card key={feature.title}>
<CardContent className="p-6 text-center">
<div className="bg-primary text-primary-foreground w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4">
<feature.icon className="h-8 w-8" />
</div>
<h4 className="text-xl font-semibold mb-2">{feature.title}</h4>
<p className="text-muted-foreground text-sm">{feature.description}</p>
</CardContent>
</Card>
))}
</div>
</div>
</section>
{/* Occasions Section */}
<section className="py-16">
<div className="container mx-auto px-4">
<h3 className="text-3xl font-bold text-center mb-8">Perfect for Any Occasion</h3>
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-4 max-w-5xl mx-auto">
{[
"Weddings",
"Birthdays",
"Baby Showers",
"Graduations",
"Anniversaries",
"Corporate Events",
"Holidays",
"Thank You Cards",
"Invitations",
"Save the Dates",
"Baptisms",
"Realtors", // Changed from "Real Estate" to "Realtors"
].map((occasion) => (
<div
key={occasion}
className="bg-card border rounded-lg p-4 text-center hover:shadow-md transition-shadow"
>
<p className="font-medium text-sm">{occasion}</p>
</div>
))}
</div>
</div>
</section>
{/* CTA Section */}
<section className="py-16 bg-secondary text-secondary-foreground">
<div className="container mx-auto px-4 text-center">
<h3 className="text-3xl font-bold mb-4">Ready to Create Your Custom Card?</h3>
<p className="text-lg mb-8 max-w-2xl mx-auto opacity-90">
Contact us today to discuss your custom card needs and get started on your unique design
</p>
<div className="flex gap-4 justify-center flex-wrap">
<Button
size="lg"
variant="outline"
asChild
className="bg-secondary-foreground/10 hover:bg-secondary-foreground/20 border-secondary-foreground/20"
>
<Link href="/contact">Contact Us</Link>
</Button>
<Button
size="lg"
variant="outline"
asChild
className="bg-secondary-foreground/10 hover:bg-secondary-foreground/20 border-secondary-foreground/20"
>
<Link href="/our-cards">Browse Our Cards</Link>
</Button>
</div>
</div>
</section>
</main>
</>
)
}

141
app/globals.css Normal file
View File

@ -0,0 +1,141 @@
@import "tailwindcss";
@import "tw-animate-css";
@custom-variant dark (&:is(.dark *));
:root {
/* Warm cream background */
--background: oklch(0.98 0.01 85);
--foreground: oklch(0.25 0.02 30);
/* Card backgrounds */
--card: oklch(1 0 0);
--card-foreground: oklch(0.25 0.02 30);
/* Popover */
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.25 0.02 30);
/* Primary - Red brand color */
--primary: oklch(0.52 0.21 25);
--primary-foreground: oklch(0.99 0 0);
/* Secondary - Blue accent */
--secondary: oklch(0.45 0.12 250);
--secondary-foreground: oklch(0.99 0 0);
/* Muted */
--muted: oklch(0.95 0.01 85);
--muted-foreground: oklch(0.5 0.02 30);
/* Accent - Light blue */
--accent: oklch(0.92 0.03 240);
--accent-foreground: oklch(0.25 0.02 30);
/* Destructive */
--destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(0.99 0 0);
/* Border */
--border: oklch(0.88 0.01 85);
--input: oklch(0.88 0.01 85);
--ring: oklch(0.52 0.21 25);
--radius: 0.375rem;
--sidebar: oklch(1 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.145 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.145 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.985 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.396 0.141 25.723);
--destructive-foreground: oklch(0.637 0.237 25.331);
--border: oklch(0.269 0 0);
--input: oklch(0.269 0 0);
--ring: oklch(0.439 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(0.269 0 0);
--sidebar-ring: oklch(0.439 0 0);
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
}

32
app/layout.tsx Normal file
View File

@ -0,0 +1,32 @@
import type React from "react"
import type { Metadata } from "next"
import { GeistSans } from "geist/font/sans"
import { GeistMono } from "geist/font/mono"
import { Analytics } from "@vercel/analytics/next"
import { Suspense } from "react"
import { SiteHeader } from "@/components/site-header"
import { SiteFooter } from "@/components/site-footer"
import "./globals.css"
export const metadata: Metadata = {
title: "Paper Presents - Canadian Greeting Cards",
description: "Quality greeting cards for every occasion, satisfaction guaranteed",
generator: "v0.app",
}
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode
}>) {
return (
<html lang="en">
<body className={`font-sans ${GeistSans.variable} ${GeistMono.variable}`}>
<SiteHeader />
<Suspense fallback={null}>{children}</Suspense>
<SiteFooter />
<Analytics />
</body>
</html>
)
}

96
app/our-cards/page.tsx Normal file
View File

@ -0,0 +1,96 @@
import { PageHero } from "@/components/page-hero"
import { Card, CardContent } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import Link from "next/link"
import { categories, getCardsByCategory } from "@/data/cards"
export default function OurCardsPage() {
const categoryData = categories.map((category) => ({
...category,
count: getCardsByCategory(category.slug).length,
image: `/category-${category.slug}.jpg`,
href: `/category/${category.slug}`,
}))
return (
<>
<PageHero title="Our Cards" breadcrumbs={[{ label: "Home", href: "/" }]} />
<main className="flex-1">
<section className="py-16">
<div className="container mx-auto px-4">
<div className="text-center mb-12">
<p className="text-lg text-muted-foreground max-w-3xl mx-auto">
Browse our extensive collection of greeting cards for every occasion. Each card is thoughtfully designed
and printed on premium paper stock.
</p>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
{categoryData.map((category) => (
<Link key={category.name} href={category.href}>
<Card className="h-full hover:shadow-lg transition-shadow group">
<CardContent className="p-0">
<div className="aspect-square relative overflow-hidden rounded-t-lg">
<img
src={category.image || "/placeholder.svg"}
alt={category.name}
className="object-cover w-full h-full group-hover:scale-105 transition-transform duration-300"
/>
</div>
<div className="p-6">
<h3 className="text-xl font-semibold mb-2 group-hover:text-primary transition-colors">
{category.name}
</h3>
<p className="text-sm text-muted-foreground">{category.count} designs available</p>
</div>
</CardContent>
</Card>
</Link>
))}
</div>
</div>
</section>
{/* Featured Section */}
<section className="py-16 bg-muted">
<div className="container mx-auto px-4">
<h3 className="text-3xl font-bold text-center mb-12">Why Our Cards Stand Out</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 max-w-5xl mx-auto">
<div className="text-center">
<div className="text-4xl mb-4">🇨🇦</div>
<h4 className="text-xl font-semibold mb-2">Satisfaction Guaranteed</h4>
<p className="text-muted-foreground">We stand behind the quality of every card we sell</p>
</div>
<div className="text-center">
<div className="text-4xl mb-4">🎨</div>
<h4 className="text-xl font-semibold mb-2">Unique Designs</h4>
<p className="text-muted-foreground">Original artwork created by talented Canadian artists</p>
</div>
<div className="text-center">
<div className="text-4xl mb-4"></div>
<h4 className="text-xl font-semibold mb-2">Eco-Friendly</h4>
<p className="text-muted-foreground">
Printed on recycled paper with environmentally conscious practices
</p>
</div>
</div>
</div>
</section>
{/* CTA Section */}
<section className="py-16">
<div className="container mx-auto px-4 text-center">
<h3 className="text-3xl font-bold mb-4">Need Something Custom?</h3>
<p className="text-lg text-muted-foreground mb-8 max-w-2xl mx-auto">
We can create personalized cards for your special events and occasions
</p>
<Button size="lg" asChild>
<Link href="/custom-cards">Learn About Custom Cards</Link>
</Button>
</div>
</section>
</main>
</>
)
}

141
app/page.tsx Normal file
View File

@ -0,0 +1,141 @@
import { Button } from "@/components/ui/button"
import { Card, CardContent } from "@/components/ui/card"
import Link from "next/link"
import { Heart, Gift, Sparkles } from "lucide-react"
export default function HomePage() {
const featuredCategories = [
{
title: "Birthday Cards",
description: "Celebrate special moments with our unique birthday designs",
icon: Gift,
href: "/category/birthday",
image: "/cards/birthday/BDY-001.jpg",
},
{
title: "Wedding Cards",
description: "Elegant designs for your special day",
icon: Heart,
href: "/category/wedding",
image: "/cards/wedding/WED-001.jpg",
},
{
title: "3D Monuments",
description: "Unique 3D cards featuring iconic world landmarks",
icon: Sparkles,
href: "/category/monuments",
image: "/cards/monuments/MON-001.jpg",
},
{
title: "Valentine's Day",
description: "Share love and romance with our Valentine collection",
icon: Heart,
href: "/category/valentines",
image: "/cards/valentines/VAL-003.jpg",
},
]
return (
<main className="flex-1">
{/* Hero Section */}
<section className="bg-secondary text-secondary-foreground py-20">
<div className="container mx-auto px-4 text-center">
<h2 className="text-5xl font-bold mb-6 text-balance">Welcome to Paper Presents</h2>
<p className="text-xl mb-8 max-w-2xl mx-auto text-balance opacity-90">
Discover our collection of beautifully crafted greeting cards for every occasion. Satisfaction Guaranteed
with every purchase.
</p>
<div className="flex gap-4 justify-center flex-wrap">
<Button size="lg" asChild>
<Link href="/our-cards">Browse Our Cards</Link>
</Button>
<Button
size="lg"
variant="outline"
asChild
className="bg-secondary-foreground/10 hover:bg-secondary-foreground/20 border-secondary-foreground/20"
>
<Link href="/custom-cards">Create Custom Card</Link>
</Button>
</div>
</div>
</section>
{/* Featured Categories */}
<section className="py-16">
<div className="container mx-auto px-4">
<h3 className="text-3xl font-bold text-center mb-12">Shop by Category</h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{featuredCategories.map((category) => (
<Link key={category.title} href={category.href}>
<Card className="h-full hover:shadow-lg transition-shadow">
<CardContent className="p-0">
<div className="aspect-[4/3] relative overflow-hidden rounded-t-lg">
<img
src={category.image || "/placeholder.svg"}
alt={category.title}
className="object-cover w-full h-full"
/>
</div>
<div className="p-6">
<div className="flex items-center gap-3 mb-3">
<category.icon className="h-6 w-6 text-primary" />
<h4 className="text-xl font-semibold">{category.title}</h4>
</div>
<p className="text-muted-foreground text-sm">{category.description}</p>
</div>
</CardContent>
</Card>
</Link>
))}
</div>
</div>
</section>
{/* Why Choose Us */}
<section className="py-16 bg-muted">
<div className="container mx-auto px-4">
<h3 className="text-3xl font-bold text-center mb-12">Why Choose Paper Presents?</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 max-w-5xl mx-auto">
<div className="text-center">
<div className="bg-primary text-primary-foreground w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4">
<Heart className="h-8 w-8" />
</div>
<h4 className="text-xl font-semibold mb-2">Quality Craftsmanship</h4>
<p className="text-muted-foreground">
Each card is carefully designed and printed with premium materials
</p>
</div>
<div className="text-center">
<div className="bg-primary text-primary-foreground w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4">
<Sparkles className="h-8 w-8" />
</div>
<h4 className="text-xl font-semibold mb-2">Custom Options</h4>
<p className="text-muted-foreground">Personalize any card to make it uniquely yours</p>
</div>
<div className="text-center">
<div className="bg-primary text-primary-foreground w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4">
<Gift className="h-8 w-8" />
</div>
<h4 className="text-xl font-semibold mb-2">Satisfaction Guaranteed</h4>
<p className="text-muted-foreground">We stand behind the quality of every card we sell</p>
</div>
</div>
</div>
</section>
{/* CTA Section */}
<section className="py-16">
<div className="container mx-auto px-4 text-center">
<h3 className="text-3xl font-bold mb-4">Ready to Find the Perfect Card?</h3>
<p className="text-lg text-muted-foreground mb-8 max-w-2xl mx-auto">
Browse our extensive collection or create a custom design that's uniquely yours
</p>
<Button size="lg" asChild>
<Link href="/our-cards">Start Shopping</Link>
</Button>
</div>
</section>
</main>
)
}

View File

@ -0,0 +1,87 @@
import { SiteHeader } from "@/components/site-header"
import { SiteFooter } from "@/components/site-footer"
import { PageHero } from "@/components/page-hero"
import Link from "next/link"
import Image from "next/image"
const categories = [
{
name: "Birthday",
slug: "birthday",
image: "/cards/birthday/BDY-001.jpg",
description: "Celebrate with our pop-up birthday cards",
},
{
name: "Christmas",
slug: "christmas",
image: "/cards/christmas/CHR-001.jpg",
description: "Festive 3D Christmas greetings",
},
{
name: "Valentine's Day",
slug: "valentines-day",
image: "/cards/valentines/VAL-001.jpg",
description: "Express your love with our Valentine cards",
},
{
name: "Wedding",
slug: "wedding",
image: "/cards/wedding/WED-001.jpg",
description: "Elegant wedding celebration cards",
},
{
name: "Baby",
slug: "baby",
image: "/cards/baby/BBY-001.jpg",
description: "Welcome the new arrival",
},
{
name: "3D Monuments",
slug: "monuments",
image: "/cards/monuments/MON-001.jpg",
description: "Iconic landmarks in 3D",
},
{
name: "Sentiments",
slug: "sentiments",
image: "/cards/sentiments/SEN-001.jpg",
description: "Thank you, get well, and more",
},
{
name: "Specialty",
slug: "specialty",
image: "/cards/specialty/SPC-002.jpg",
description: "Unique cards for special moments",
},
]
export default function YourOccasionsPage() {
return (
<>
<SiteHeader />
<PageHero title="Your Occasions" breadcrumbs={[{ label: "Home", href: "/" }]} />
<div className="container mx-auto px-4 py-12">
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-8">
{categories.map((category) => (
<Link key={category.slug} href={`/category/${category.slug}`} className="group">
<div className="relative aspect-[150/185] overflow-hidden rounded-lg border-2 border-border hover:border-primary transition-colors">
<Image
src={category.image || "/placeholder.svg"}
alt={category.name}
fill
className="object-cover group-hover:scale-105 transition-transform duration-300"
/>
</div>
<h3 className="mt-3 text-center font-semibold text-lg group-hover:text-primary transition-colors">
{category.name}
</h3>
<p className="text-center text-sm text-muted-foreground mt-1">{category.description}</p>
</Link>
))}
</div>
</div>
<SiteFooter />
</>
)
}

21
components.json Normal file
View File

@ -0,0 +1,21 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "",
"css": "app/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}

28
components/page-hero.tsx Normal file
View File

@ -0,0 +1,28 @@
interface PageHeroProps {
title: string
breadcrumbs?: { label: string; href: string }[]
}
export function PageHero({ title, breadcrumbs }: PageHeroProps) {
return (
<div className="bg-secondary text-secondary-foreground py-12">
<div className="container mx-auto px-4">
<h1 className="text-4xl font-bold text-center mb-4">{title}</h1>
{breadcrumbs && (
<nav className="flex items-center justify-center gap-2 text-sm">
{breadcrumbs.map((crumb, index) => (
<div key={crumb.href} className="flex items-center gap-2">
<a href={crumb.href} className="hover:underline opacity-90">
{crumb.label}
</a>
{index < breadcrumbs.length - 1 && <span className="opacity-70">»</span>}
</div>
))}
<span className="opacity-70">»</span>
<span className="font-medium">{title}</span>
</nav>
)}
</div>
</div>
)
}

View File

@ -0,0 +1,44 @@
import Link from "next/link"
import Image from "next/image"
export function SiteFooter() {
const categories = [
{ name: "3D Monuments", href: "/category/3d-monuments" },
{ name: "Baby", href: "/category/baby" },
{ name: "Basket", href: "/category/basket" },
{ name: "Birthday", href: "/category/birthday" },
{ name: "Christmas", href: "/category/christmas" },
{ name: "My Account", href: "/account" },
{ name: "Sentiments", href: "/category/sentiments" },
{ name: "Shop", href: "/shop" },
{ name: "Specialty", href: "/category/specialty" },
{ name: "Valentines Day", href: "/category/valentines" },
{ name: "Wedding Cards", href: "/category/wedding" },
]
return (
<footer className="border-t bg-card mt-16">
<div className="container mx-auto px-4 py-8">
<div className="flex justify-center mb-6">
<Link href="/">
<Image src="/logo.png" alt="Paper Presents" width={240} height={43} className="h-10 w-auto" />
</Link>
</div>
<nav className="flex flex-wrap items-center justify-center gap-4 text-sm">
{categories.map((category, index) => (
<div key={category.name} className="flex items-center gap-4">
<Link href={category.href} className="hover:text-primary transition-colors">
{category.name}
</Link>
{index < categories.length - 1 && <span className="text-muted-foreground"></span>}
</div>
))}
</nav>
<div className="text-center mt-6 text-sm text-muted-foreground">
Paper Presents | © {new Date().getFullYear()}
</div>
</div>
</footer>
)
}

View File

@ -0,0 +1,86 @@
import Link from "next/link"
import Image from "next/image"
import { Search, ShoppingCart } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
export function SiteHeader() {
return (
<header className="border-b bg-card">
<div className="container mx-auto px-4">
{/* Top bar with logo and utility links */}
<div className="flex items-center justify-between py-4">
<Link href="/" className="flex items-center">
<Image src="/logo.png" alt="Paper Presents" width={280} height={50} className="h-12 w-auto" priority />
</Link>
<nav className="hidden md:flex items-center gap-6">
<Link href="/our-promise" className="text-sm hover:text-primary transition-colors">
Our Promise
</Link>
<Link href="/faq" className="text-sm hover:text-primary transition-colors">
FAQ
</Link>
<Link href="/about" className="text-sm hover:text-primary transition-colors">
About Us
</Link>
<Link href="/contact" className="text-sm hover:text-primary transition-colors">
Contact Us
</Link>
</nav>
<div className="flex items-center gap-4">
<div className="hidden md:flex items-center gap-2">
<Input type="search" placeholder="Search..." className="w-48" />
<Button size="icon" variant="ghost">
<Search className="h-4 w-4" />
</Button>
</div>
<Button size="icon" variant="ghost" className="relative">
<ShoppingCart className="h-5 w-5" />
<span className="absolute -top-1 -right-1 bg-primary text-primary-foreground text-xs rounded-full h-5 w-5 flex items-center justify-center">
0
</span>
</Button>
</div>
</div>
{/* Main navigation */}
<nav className="border-t py-3">
<ul className="flex flex-wrap items-center justify-center gap-6 text-sm">
<li></li>
<li>
<Link href="/our-cards" className="hover:text-primary transition-colors font-medium">
Our Cards
</Link>
</li>
<li className="text-muted-foreground">|</li>
<li>
<Link href="/your-occasions" className="hover:text-primary transition-colors font-medium">
Your Occasions
</Link>
</li>
<li className="text-muted-foreground">|</li>
<li>
<Link href="/custom-cards" className="hover:text-primary transition-colors font-medium">
Custom Cards
</Link>
</li>
<li className="text-muted-foreground">|</li>
<li>
<Link href="/wholesale" className="hover:text-primary transition-colors font-medium">
Wholesale Orders
</Link>
</li>
<li className="ml-auto">
<Button asChild className="bg-primary hover:bg-primary/90 text-primary-foreground">
<Link href="/checkout">Checkout</Link>
</Button>
</li>
</ul>
</nav>
</div>
</header>
)
}

View File

@ -0,0 +1,11 @@
'use client'
import * as React from 'react'
import {
ThemeProvider as NextThemesProvider,
type ThemeProviderProps,
} from 'next-themes'
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
}

46
components/ui/badge.tsx Normal file
View File

@ -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 '@/lib/utils'
const badgeVariants = cva(
'inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-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 transition-[color,box-shadow] overflow-hidden',
{
variants: {
variant: {
default:
'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90',
secondary:
'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90',
destructive:
'border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
outline:
'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground',
},
},
defaultVariants: {
variant: 'default',
},
},
)
function Badge({
className,
variant,
asChild = false,
...props
}: React.ComponentProps<'span'> &
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
const Comp = asChild ? Slot : 'span'
return (
<Comp
data-slot="badge"
className={cn(badgeVariants({ variant }), className)}
{...props}
/>
)
}
export { Badge, badgeVariants }

60
components/ui/button.tsx Normal file
View File

@ -0,0 +1,60 @@
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 hover:bg-primary/90',
destructive:
'bg-destructive text-white 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 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',
'icon-sm': 'size-8',
'icon-lg': 'size-10',
},
},
defaultVariants: {
variant: 'default',
size: 'default',
},
},
)
function Button({
className,
variant,
size,
asChild = false,
...props
}: React.ComponentProps<'button'> &
VariantProps<typeof buttonVariants> & {
asChild?: boolean
}) {
const Comp = asChild ? Slot : 'button'
return (
<Comp
data-slot="button"
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
)
}
export { Button, buttonVariants }

92
components/ui/card.tsx Normal file
View File

@ -0,0 +1,92 @@
import * as React from 'react'
import { cn } from '@/lib/utils'
function Card({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="card"
className={cn(
'bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm',
className,
)}
{...props}
/>
)
}
function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="card-header"
className={cn(
'@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6',
className,
)}
{...props}
/>
)
}
function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="card-title"
className={cn('leading-none font-semibold', className)}
{...props}
/>
)
}
function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="card-description"
className={cn('text-muted-foreground text-sm', className)}
{...props}
/>
)
}
function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="card-action"
className={cn(
'col-start-2 row-span-2 row-start-1 self-start justify-self-end',
className,
)}
{...props}
/>
)
}
function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="card-content"
className={cn('px-6', className)}
{...props}
/>
)
}
function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="card-footer"
className={cn('flex items-center px-6 [.border-t]:pt-6', className)}
{...props}
/>
)
}
export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardAction,
CardDescription,
CardContent,
}

21
components/ui/input.tsx Normal file
View File

@ -0,0 +1,21 @@
import * as React from 'react'
import { cn } from '@/lib/utils'
function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
return (
<input
type={type}
data-slot="input"
className={cn(
'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
'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',
className,
)}
{...props}
/>
)
}
export { Input }

24
components/ui/label.tsx Normal file
View File

@ -0,0 +1,24 @@
'use client'
import * as React from 'react'
import * as LabelPrimitive from '@radix-ui/react-label'
import { cn } from '@/lib/utils'
function Label({
className,
...props
}: React.ComponentProps<typeof LabelPrimitive.Root>) {
return (
<LabelPrimitive.Root
data-slot="label"
className={cn(
'flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',
className,
)}
{...props}
/>
)
}
export { Label }

185
components/ui/select.tsx Normal file
View File

@ -0,0 +1,185 @@
'use client'
import * as React from 'react'
import * as SelectPrimitive from '@radix-ui/react-select'
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from 'lucide-react'
import { cn } from '@/lib/utils'
function Select({
...props
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
return <SelectPrimitive.Root data-slot="select" {...props} />
}
function SelectGroup({
...props
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
return <SelectPrimitive.Group data-slot="select-group" {...props} />
}
function SelectValue({
...props
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
return <SelectPrimitive.Value data-slot="select-value" {...props} />
}
function SelectTrigger({
className,
size = 'default',
children,
...props
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
size?: 'sm' | 'default'
}) {
return (
<SelectPrimitive.Trigger
data-slot="select-trigger"
data-size={size}
className={cn(
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className,
)}
{...props}
>
{children}
<SelectPrimitive.Icon asChild>
<ChevronDownIcon className="size-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
)
}
function SelectContent({
className,
children,
position = 'popper',
...props
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
return (
<SelectPrimitive.Portal>
<SelectPrimitive.Content
data-slot="select-content"
className={cn(
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md',
position === 'popper' &&
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
className,
)}
position={position}
{...props}
>
<SelectScrollUpButton />
<SelectPrimitive.Viewport
className={cn(
'p-1',
position === 'popper' &&
'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1',
)}
>
{children}
</SelectPrimitive.Viewport>
<SelectScrollDownButton />
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
)
}
function SelectLabel({
className,
...props
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
return (
<SelectPrimitive.Label
data-slot="select-label"
className={cn('text-muted-foreground px-2 py-1.5 text-xs', className)}
{...props}
/>
)
}
function SelectItem({
className,
children,
...props
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
return (
<SelectPrimitive.Item
data-slot="select-item"
className={cn(
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
className,
)}
{...props}
>
<span className="absolute right-2 flex size-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<CheckIcon className="size-4" />
</SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
)
}
function SelectSeparator({
className,
...props
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
return (
<SelectPrimitive.Separator
data-slot="select-separator"
className={cn('bg-border pointer-events-none -mx-1 my-1 h-px', className)}
{...props}
/>
)
}
function SelectScrollUpButton({
className,
...props
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
return (
<SelectPrimitive.ScrollUpButton
data-slot="select-scroll-up-button"
className={cn(
'flex cursor-default items-center justify-center py-1',
className,
)}
{...props}
>
<ChevronUpIcon className="size-4" />
</SelectPrimitive.ScrollUpButton>
)
}
function SelectScrollDownButton({
className,
...props
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
return (
<SelectPrimitive.ScrollDownButton
data-slot="select-scroll-down-button"
className={cn(
'flex cursor-default items-center justify-center py-1',
className,
)}
{...props}
>
<ChevronDownIcon className="size-4" />
</SelectPrimitive.ScrollDownButton>
)
}
export {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectScrollDownButton,
SelectScrollUpButton,
SelectSeparator,
SelectTrigger,
SelectValue,
}

845
data/cards.ts Normal file
View File

@ -0,0 +1,845 @@
export interface Card {
id: string
name: string
orderCode: string
price: number
category: string
image: string
description?: string
variants?: string[]
}
export const cards: Card[] = [
// Baby Cards
{
id: "bby-001",
name: "Baby Congratulations",
orderCode: "BBY-001",
price: 6.99,
category: "baby",
image: "/cards/baby/BBY-001.jpg",
},
{
id: "bby-002",
name: "New Baby Celebration",
orderCode: "BBY-002",
price: 6.99,
category: "baby",
image: "/cards/baby/BBY-002.jpg",
},
{
id: "bby-003",
name: "It's a Girl",
orderCode: "BBY-003",
price: 5.99,
category: "baby",
image: "/cards/baby/BBY-003.jpg",
variants: ["It's a Boy - BBY-004"],
},
{
id: "bby-004",
name: "It's a Boy",
orderCode: "BBY-004",
price: 5.99,
category: "baby",
image: "/cards/baby/BBY-004.jpg",
},
{
id: "bby-005",
name: "Welcome Baby",
orderCode: "BBY-005",
price: 5.99,
category: "baby",
image: "/cards/baby/BBY-005.jpg",
},
// Birthday Cards
{
id: "bdy-001",
name: "Cake",
orderCode: "BDY-001",
price: 6.99,
category: "birthday",
image: "/cards/birthday/BDY-001.jpg",
description: 'Card Inscription: "Happy Birthday"',
},
{
id: "bdy-002",
name: "Piano",
orderCode: "BDY-002",
price: 6.99,
category: "birthday",
image: "/cards/birthday/BDY-002.jpg",
description: 'Card Inscription: "Happy Birthday"',
},
{
id: "bdy-003",
name: "Birthday Star",
orderCode: "BDY-003",
price: 6.99,
category: "birthday",
image: "/cards/birthday/BDY-003.jpg",
},
{
id: "bdy-004",
name: "Train",
orderCode: "BDY-004",
price: 6.99,
category: "birthday",
image: "/cards/birthday/BDY-004.jpg",
description: 'Card Inscription: "Happy Birthday"',
},
{
id: "bdy-005",
name: "Hummingbird",
orderCode: "BDY-005",
price: 6.99,
category: "birthday",
image: "/cards/birthday/BDY-005.jpg",
description: 'Card Inscription: "Happy Birthday"',
},
{
id: "bdy-006",
name: "Fortress",
orderCode: "BDY-006",
price: 7.99,
category: "birthday",
image: "/cards/birthday/BDY-006.jpg",
description: 'Card Inscription: "Happy Birthday!"',
},
{
id: "bdy-007",
name: "Ferris Wheel",
orderCode: "BDY-007",
price: 7.99,
category: "birthday",
image: "/cards/birthday/BDY-007.jpg",
},
{
id: "bdy-008",
name: "Train 1",
orderCode: "BDY-008",
price: 6.99,
category: "birthday",
image: "/cards/birthday/BDY-008.jpg",
},
{
id: "bdy-009",
name: "Sailboat",
orderCode: "BDY-009",
price: 6.99,
category: "birthday",
image: "/cards/birthday/BDY-009.jpg",
description: 'Card Inscription: "Happy Birthday!"',
},
{
id: "bdy-010",
name: "Presents",
orderCode: "BDY-010",
price: 6.99,
category: "birthday",
image: "/cards/birthday/BDY-010.jpg",
description: 'Card Inscription: "Happy Birthday"',
},
{
id: "bdy-011",
name: "Train 2",
orderCode: "BDY-011",
price: 6.99,
category: "birthday",
image: "/cards/birthday/BDY-011.jpg",
description: 'Card Inscription: "Happy Birthday!"',
},
{
id: "bdy-012",
name: "Owl",
orderCode: "BDY-012",
price: 6.99,
category: "birthday",
image: "/cards/birthday/BDY-012.jpg",
description: 'Card Inscription: "Happy Birthday"',
},
{
id: "bdy-013",
name: "Bday Bear",
orderCode: "BDY-013",
price: 6.99,
category: "birthday",
image: "/cards/birthday/BDY-013.jpg",
},
{
id: "bdy-014",
name: "Cake 2",
orderCode: "BDY-014",
price: 7.99,
category: "birthday",
image: "/cards/birthday/BDY-014.jpg",
},
{
id: "bdy-015",
name: "Cat Love",
orderCode: "BDY-015",
price: 6.99,
category: "birthday",
image: "/cards/birthday/BDY-015.jpg",
description: 'Card Inscription: "Happy Birthday"',
},
{
id: "bdy-016",
name: "Gift Tractor",
orderCode: "BDY-016",
price: 6.99,
category: "birthday",
image: "/cards/birthday/BDY-016.jpg",
},
// Christmas Cards
{
id: "chr-001",
name: "Christmas Greetings",
orderCode: "CHR-001",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-001.jpg",
},
{
id: "chr-002",
name: "Holiday Wishes",
orderCode: "CHR-002",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-002.jpg",
},
{
id: "chr-003",
name: "Merry Christmas",
orderCode: "CHR-003",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-003.jpg",
},
{
id: "chr-004",
name: "Season's Greetings",
orderCode: "CHR-004",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-004.jpg",
},
{
id: "chr-005",
name: "Christmas Joy",
orderCode: "CHR-005",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-005.jpg",
},
{
id: "chr-006",
name: "Holiday Cheer",
orderCode: "CHR-006",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-006.jpg",
},
{
id: "chr-007",
name: "Christmas Blessings",
orderCode: "CHR-007",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-007.jpg",
},
{
id: "chr-008",
name: "Winter Wishes",
orderCode: "CHR-008",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-008.jpg",
},
{
id: "chr-009",
name: "Christmas Magic",
orderCode: "CHR-009",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-009.jpg",
},
{
id: "chr-010",
name: "Holiday Spirit",
orderCode: "CHR-010",
price: 6.99,
category: "christmas",
image: "/cards/christmas/CHR-010.jpg",
},
{
id: "chr-011",
name: "Christmas Wonder",
orderCode: "CHR-011",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-011.jpg",
},
{
id: "chr-012",
name: "Festive Greetings",
orderCode: "CHR-012",
price: 6.99,
category: "christmas",
image: "/cards/christmas/CHR-012.jpg",
},
{
id: "chr-013",
name: "Christmas Peace",
orderCode: "CHR-013",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-013.jpg",
},
{
id: "chr-014",
name: "Holiday Happiness",
orderCode: "CHR-014",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-014.jpg",
},
{
id: "chr-015",
name: "Christmas Elegance",
orderCode: "CHR-015",
price: 6.99,
category: "christmas",
image: "/cards/christmas/CHR-015.jpg",
},
{
id: "chr-016",
name: "Winter Celebration",
orderCode: "CHR-016",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-016.jpg",
},
{
id: "chr-017",
name: "Christmas Delight",
orderCode: "CHR-017",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-017.jpg",
},
{
id: "chr-018",
name: "Holiday Joy",
orderCode: "CHR-018",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-018.jpg",
},
{
id: "chr-019",
name: "Christmas Sparkle",
orderCode: "CHR-019",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-019.jpg",
},
{
id: "chr-020",
name: "Festive Season",
orderCode: "CHR-020",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-020.jpg",
},
{
id: "chr-021",
name: "Christmas Warmth",
orderCode: "CHR-021",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-021.jpg",
},
{
id: "chr-022",
name: "Holiday Elegance",
orderCode: "CHR-022",
price: 6.99,
category: "christmas",
image: "/cards/christmas/CHR-022.jpg",
},
{
id: "chr-023",
name: "Christmas Charm",
orderCode: "CHR-023",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-023.jpg",
},
{
id: "chr-024",
name: "Winter Blessings",
orderCode: "CHR-024",
price: 5.99,
category: "christmas",
image: "/cards/christmas/CHR-024.jpg",
},
// Monuments Cards
{
id: "mon-001",
name: "Notre Dame",
orderCode: "MON-001",
price: 9.99,
category: "monuments",
image: "/cards/monuments/MON-001.jpg",
description: 'Card Inscription: "Notre Dame"',
},
{
id: "mon-002",
name: "Petronas Towers",
orderCode: "MON-002",
price: 7.99,
category: "monuments",
image: "/cards/monuments/MON-002.jpg",
description: 'Card Inscription: "Malaysia"',
},
{
id: "mon-003",
name: "Le Louvre",
orderCode: "MON-003",
price: 7.99,
category: "monuments",
image: "/cards/monuments/MON-003.jpg",
description: 'Card Inscription: "Le Louvre"',
},
{
id: "mon-004",
name: "Coliseum",
orderCode: "MON-004",
price: 7.99,
category: "monuments",
image: "/cards/monuments/MON-004.jpg",
description: "Card Inscription: none",
},
{
id: "mon-005",
name: "Eiffel Tower",
orderCode: "MON-005",
price: 7.99,
category: "monuments",
image: "/cards/monuments/MON-005.jpg",
description: 'Card Inscription: "France"',
},
{
id: "mon-006",
name: "Sydney Opera House",
orderCode: "MON-006",
price: 6.99,
category: "monuments",
image: "/cards/monuments/MON-006.jpg",
description: "Card Inscription: none",
},
{
id: "mon-007",
name: "Arc de Triomphe",
orderCode: "MON-007",
price: 6.99,
category: "monuments",
image: "/cards/monuments/MON-007.jpg",
description: "Card Inscription: none",
},
{
id: "mon-008",
name: "Ancient Library",
orderCode: "MON-008",
price: 6.99,
category: "monuments",
image: "/cards/monuments/MON-008.jpg",
description: "Card Inscription: none",
},
// Sentiments Cards
{
id: "sen-001",
name: "Thank You",
orderCode: "SEN-001",
price: 5.99,
category: "sentiments",
image: "/cards/sentiments/SEN-001.jpg",
description: "Available: Thank you, Get Well Soon & Happy Mother's Day",
},
{
id: "sen-002",
name: "Get Well Soon",
orderCode: "SEN-002",
price: 5.99,
category: "sentiments",
image: "/cards/sentiments/SEN-002.jpg",
description: "Available: Thank you, Get Well Soon & Happy Mother's Day",
},
{
id: "sen-003",
name: "Happy Mother's Day",
orderCode: "SEN-003",
price: 5.99,
category: "sentiments",
image: "/cards/sentiments/SEN-003.jpg",
description: "Available: Thank you, Get Well Soon & Happy Mother's Day",
},
{
id: "sen-004",
name: "Thank You Collection",
orderCode: "SEN-004",
price: 5.99,
category: "sentiments",
image: "/cards/sentiments/SEN-004.jpg",
description: "Available: Thank you, Get Well Soon & Happy Mother's Day",
},
{
id: "sen-005",
name: "Get Well Collection",
orderCode: "SEN-005",
price: 5.99,
category: "sentiments",
image: "/cards/sentiments/SEN-005.jpg",
description: "Available: Thank you, Get Well Soon & Happy Mother's Day",
},
{
id: "sen-006",
name: "Mother's Day Collection",
orderCode: "SEN-006",
price: 5.99,
category: "sentiments",
image: "/cards/sentiments/SEN-006.jpg",
description: "Available: Thank you, Get Well Soon & Happy Mother's Day",
},
{
id: "sen-007",
name: "Heartfelt Sentiments",
orderCode: "SEN-007",
price: 5.99,
category: "sentiments",
image: "/cards/sentiments/SEN-007.jpg",
},
{
id: "sen-008",
name: "Warm Wishes",
orderCode: "SEN-008",
price: 5.99,
category: "sentiments",
image: "/cards/sentiments/SEN-008.jpg",
},
{
id: "sen-009",
name: "Special Thoughts",
orderCode: "SEN-009",
price: 5.99,
category: "sentiments",
image: "/cards/sentiments/SEN-009.jpg",
},
// Specialty Cards
{
id: "spc-002",
name: "Special Occasion",
orderCode: "SPC-002",
price: 5.99,
category: "specialty",
image: "/cards/specialty/SPC-002.jpg",
},
{
id: "spc-004",
name: "Unique Design",
orderCode: "SPC-004",
price: 5.99,
category: "specialty",
image: "/cards/specialty/SPC-004.jpg",
},
{
id: "spc-005",
name: "Premium Specialty",
orderCode: "SPC-005",
price: 6.99,
category: "specialty",
image: "/cards/specialty/SPC-005.jpg",
},
{
id: "spc-006",
name: "Elegant Specialty",
orderCode: "SPC-006",
price: 6.99,
category: "specialty",
image: "/cards/specialty/SPC-006.jpg",
},
{
id: "spc-007",
name: "Special Moments",
orderCode: "SPC-007",
price: 5.99,
category: "specialty",
image: "/cards/specialty/SPC-007.jpg",
},
{
id: "spc-008",
name: "Distinctive Design",
orderCode: "SPC-008",
price: 6.99,
category: "specialty",
image: "/cards/specialty/SPC-008.jpg",
},
{
id: "spc-009",
name: "Specialty Collection",
orderCode: "SPC-009",
price: 0.99,
category: "specialty",
image: "/cards/specialty/SPC-009.jpg",
},
// Valentine's Day Cards
{
id: "val-001",
name: "Valentine Love",
orderCode: "VAL-001",
price: 5.99,
category: "valentines",
image: "/cards/valentines/VAL-001.jpg",
},
{
id: "val-002",
name: "Be My Valentine",
orderCode: "VAL-002",
price: 5.99,
category: "valentines",
image: "/cards/valentines/VAL-002.jpg",
},
{
id: "val-003",
name: "Love & Romance",
orderCode: "VAL-003",
price: 6.99,
category: "valentines",
image: "/cards/valentines/VAL-003.jpg",
},
{
id: "val-004",
name: "Valentine Wishes",
orderCode: "VAL-004",
price: 6.99,
category: "valentines",
image: "/cards/valentines/VAL-004.jpg",
},
{
id: "val-005",
name: "Sweet Valentine",
orderCode: "VAL-005",
price: 6.99,
category: "valentines",
image: "/cards/valentines/VAL-005.jpg",
},
{
id: "val-006",
name: "Valentine Joy",
orderCode: "VAL-006",
price: 5.99,
category: "valentines",
image: "/cards/valentines/VAL-006.jpg",
},
{
id: "val-007",
name: "Love Always",
orderCode: "VAL-007",
price: 5.99,
category: "valentines",
image: "/cards/valentines/VAL-007.jpg",
},
{
id: "val-008",
name: "Valentine Hearts",
orderCode: "VAL-008",
price: 5.99,
category: "valentines",
image: "/cards/valentines/VAL-008.jpg",
},
{
id: "val-009",
name: "Romantic Wishes",
orderCode: "VAL-009",
price: 5.99,
category: "valentines",
image: "/cards/valentines/VAL-009.jpg",
},
{
id: "val-010",
name: "Valentine Bliss",
orderCode: "VAL-010",
price: 5.99,
category: "valentines",
image: "/cards/valentines/VAL-010.jpg",
},
{
id: "val-011",
name: "Love & Happiness",
orderCode: "VAL-011",
price: 5.99,
category: "valentines",
image: "/cards/valentines/VAL-011.jpg",
},
{
id: "val-012",
name: "Valentine Charm",
orderCode: "VAL-012",
price: 5.99,
category: "valentines",
image: "/cards/valentines/VAL-012.jpg",
},
{
id: "val-013",
name: "Sweetheart",
orderCode: "VAL-013",
price: 5.99,
category: "valentines",
image: "/cards/valentines/VAL-013.jpg",
},
{
id: "val-014",
name: "Valentine Delight",
orderCode: "VAL-014",
price: 5.99,
category: "valentines",
image: "/cards/valentines/VAL-014.jpg",
},
{
id: "val-015",
name: "Love Notes",
orderCode: "VAL-015",
price: 5.99,
category: "valentines",
image: "/cards/valentines/VAL-015.jpg",
},
{
id: "val-016",
name: "Valentine Elegance",
orderCode: "VAL-016",
price: 6.99,
category: "valentines",
image: "/cards/valentines/VAL-016.jpg",
},
{
id: "val-017",
name: "Forever Love",
orderCode: "VAL-017",
price: 5.99,
category: "valentines",
image: "/cards/valentines/VAL-017.jpg",
},
// Wedding Cards
{
id: "wed-001",
name: "Wedding Congratulations",
orderCode: "WED-001",
price: 5.99,
category: "wedding",
image: "/cards/wedding/WED-001.jpg",
},
{
id: "wed-002",
name: "Happy Wedding Day",
orderCode: "WED-002",
price: 5.99,
category: "wedding",
image: "/cards/wedding/WED-002.jpg",
},
{
id: "wed-003",
name: "Wedding Wishes",
orderCode: "WED-003",
price: 5.99,
category: "wedding",
image: "/cards/wedding/WED-003.jpg",
},
{
id: "wed-004",
name: "Wedding Celebration",
orderCode: "WED-004",
price: 5.99,
category: "wedding",
image: "/cards/wedding/WED-004.jpg",
},
{
id: "wed-005",
name: "Custom Wedding Card",
orderCode: "WED-005",
price: 0,
category: "wedding",
image: "/cards/wedding/WED-005.jpg",
description: "Custom messages available - Please inquire for pricing",
},
{
id: "wed-006",
name: "Wedding Bliss",
orderCode: "WED-006",
price: 5.99,
category: "wedding",
image: "/cards/wedding/WED-006.jpg",
},
]
export const categories = [
{
slug: "baby",
name: "Baby",
description: "Celebrate new arrivals with our adorable baby cards",
},
{
slug: "birthday",
name: "Birthday",
description: "Make their special day memorable with our birthday collection",
},
{
slug: "christmas",
name: "Christmas",
description: "Spread holiday cheer with our festive Christmas cards",
},
{
slug: "monuments",
name: "3D Monuments",
description: "Unique 3D cards featuring iconic landmarks",
},
{
slug: "sentiments",
name: "Sentiments",
description: "Express your feelings with our heartfelt sentiment cards",
},
{
slug: "specialty",
name: "Specialty",
description: "Distinctive designs for unique occasions",
},
{
slug: "valentines",
name: "Valentine's Day",
description: "Share love and romance with our Valentine collection",
},
{
slug: "wedding",
name: "Wedding",
description: "Congratulate the happy couple with elegant wedding cards",
},
]
export function getCardsByCategory(category: string): Card[] {
return cards.filter((card) => card.category === category)
}
export function getCategoryBySlug(slug: string) {
return categories.find((cat) => cat.slug === slug)
}
export function getCardById(id: string): Card | undefined {
return cards.find((card) => card.id === id)
}

6
lib/utils.ts Normal file
View File

@ -0,0 +1,6 @@
import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}

14
next.config.mjs Normal file
View File

@ -0,0 +1,14 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
eslint: {
ignoreDuringBuilds: true,
},
typescript: {
ignoreBuildErrors: true,
},
images: {
unoptimized: true,
},
}
export default nextConfig

74
package.json Normal file
View File

@ -0,0 +1,74 @@
{
"name": "my-v0-project",
"version": "0.1.0",
"private": true,
"scripts": {
"build": "next build",
"dev": "next dev",
"lint": "next lint",
"start": "next start"
},
"dependencies": {
"@hookform/resolvers": "^3.10.0",
"@radix-ui/react-accordion": "1.2.2",
"@radix-ui/react-alert-dialog": "1.1.4",
"@radix-ui/react-aspect-ratio": "1.1.1",
"@radix-ui/react-avatar": "1.1.2",
"@radix-ui/react-checkbox": "1.1.3",
"@radix-ui/react-collapsible": "1.1.2",
"@radix-ui/react-context-menu": "2.2.4",
"@radix-ui/react-dialog": "1.1.4",
"@radix-ui/react-dropdown-menu": "2.1.4",
"@radix-ui/react-hover-card": "1.1.4",
"@radix-ui/react-label": "2.1.1",
"@radix-ui/react-menubar": "1.1.4",
"@radix-ui/react-navigation-menu": "1.2.3",
"@radix-ui/react-popover": "1.1.4",
"@radix-ui/react-progress": "1.1.1",
"@radix-ui/react-radio-group": "1.2.2",
"@radix-ui/react-scroll-area": "1.2.2",
"@radix-ui/react-select": "2.1.4",
"@radix-ui/react-separator": "1.1.1",
"@radix-ui/react-slider": "1.2.2",
"@radix-ui/react-slot": "1.1.1",
"@radix-ui/react-switch": "1.1.2",
"@radix-ui/react-tabs": "1.1.2",
"@radix-ui/react-toast": "1.2.4",
"@radix-ui/react-toggle": "1.1.1",
"@radix-ui/react-toggle-group": "1.1.1",
"@radix-ui/react-tooltip": "1.1.6",
"@vercel/analytics": "latest",
"autoprefixer": "^10.4.20",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "1.0.4",
"date-fns": "4.1.0",
"embla-carousel-react": "8.5.1",
"geist": "latest",
"input-otp": "1.4.1",
"lucide-react": "^0.454.0",
"next": "15.2.4",
"next-themes": "^0.4.6",
"react": "^19",
"react-day-picker": "9.8.0",
"react-dom": "^19",
"react-hook-form": "^7.60.0",
"react-resizable-panels": "^2.1.7",
"recharts": "2.15.4",
"sonner": "^1.7.4",
"tailwind-merge": "^2.5.5",
"tailwindcss-animate": "^1.0.7",
"vaul": "^0.9.9",
"zod": "3.25.76"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.9",
"@types/node": "^22",
"@types/react": "^19",
"@types/react-dom": "^19",
"postcss": "^8.5",
"tailwindcss": "^4.1.9",
"tw-animate-css": "1.3.3",
"typescript": "^5"
}
}

3255
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

8
postcss.config.mjs Normal file
View File

@ -0,0 +1,8 @@
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
'@tailwindcss/postcss': {},
},
}
export default config

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Some files were not shown because too many files have changed in this diff Show More