Merge version_1 into main #13

Merged
bender merged 4 commits from version_1 into main 2026-03-12 13:40:39 +00:00
4 changed files with 161 additions and 59 deletions

View File

@@ -8,7 +8,7 @@ import Link from "next/link";
import { useState } from "react";
import type { LucideIcon } from "lucide-react";
const TikTok = (props: React.SVGProps<SVGSVGElement>) => (
const TikTok = (props: React.SVGProps<SVGSVGElement>): LucideIcon => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
@@ -19,7 +19,7 @@ const TikTok = (props: React.SVGProps<SVGSVGElement>) => (
>
<path d="M19.59 6.69a4.83 4.83 0 0 1-3.77-4.25V2h-3.68v13.67a2.4 2.4 0 1 1-2.4-2.4c.34 0 .67.03 1 .09V9.41a7.12 7.12 0 0 0-1-.08C5.89 9.33 2 13.46 2 18.13s3.88 8.81 8.74 8.81c4.65 0 8.6-3.36 8.6-7.53 0-.13 0-.26 0-.39a5.5 5.5 0 0 0-.56-1.78h.09c4.87 0 8.82-3.37 8.82-7.53 0-4.16-3.96-7.53-8.82-7.53z"/>
</svg>
) as unknown as LucideIcon;
) as any;
export default function CartPage() {
const navItems = [

View File

@@ -13,7 +13,7 @@ import Link from "next/link";
import { Sparkles, TrendingUp, Instagram, Twitter, Youtube } from "lucide-react";
import type { LucideIcon } from "lucide-react";
const TikTok = (props: React.SVGProps<SVGSVGElement>) => (
const TikTok = (props: React.SVGProps<SVGSVGElement>): LucideIcon => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
@@ -24,7 +24,7 @@ const TikTok = (props: React.SVGProps<SVGSVGElement>) => (
>
<path d="M19.59 6.69a4.83 4.83 0 0 1-3.77-4.25V2h-3.68v13.67a2.4 2.4 0 1 1-2.4-2.4c.34 0 .67.03 1 .09V9.41a7.12 7.12 0 0 0-1-.08C5.89 9.33 2 13.46 2 18.13s3.88 8.81 8.74 8.81c4.65 0 8.6-3.36 8.6-7.53 0-.13 0-.26 0-.39a5.5 5.5 0 0 0-.56-1.78h.09c4.87 0 8.82-3.37 8.82-7.53 0-4.16-3.96-7.53-8.82-7.53z"/>
</svg>
) as unknown as LucideIcon;
) as any;
export default function HomePage() {
const navItems = [

View File

@@ -3,11 +3,12 @@
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarStyleCentered from "@/components/navbar/NavbarStyleCentered/NavbarStyleCentered";
import FooterCard from "@/components/sections/footer/FooterCard";
import { Instagram, Twitter, Youtube } from "lucide-react";
import { Instagram, Twitter, Youtube, Heart, ShoppingCart, Minus, Plus } from "lucide-react";
import Link from "next/link";
import { useState } from "react";
import type { LucideIcon } from "lucide-react";
const TikTok = (props: React.SVGProps<SVGSVGElement>) => (
const TikTok = (props: React.SVGProps<SVGSVGElement>): LucideIcon => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
@@ -18,29 +19,9 @@ const TikTok = (props: React.SVGProps<SVGSVGElement>) => (
>
<path d="M19.59 6.69a4.83 4.83 0 0 1-3.77-4.25V2h-3.68v13.67a2.4 2.4 0 1 1-2.4-2.4c.34 0 .67.03 1 .09V9.41a7.12 7.12 0 0 0-1-.08C5.89 9.33 2 13.46 2 18.13s3.88 8.81 8.74 8.81c4.65 0 8.6-3.36 8.6-7.53 0-.13 0-.26 0-.39a5.5 5.5 0 0 0-.56-1.78h.09c4.87 0 8.82-3.37 8.82-7.53 0-4.16-3.96-7.53-8.82-7.53z"/>
</svg>
) as unknown as LucideIcon;
const productDetails: { [key: string]: { name: string; price: number; image: string; description: string; sizes: string[]; colors: string[] } } = {
"1": {
name: "Classic Black Hoodie", price: 89.99,
image: "http://img.b2bpic.net/free-photo/medium-shot-man-posing-with-hoodie-indoors_23-2149359859.jpg", description: "Premium oversized hoodie crafted from 100% organic cotton. Perfect for layering or wearing solo. Features a kangaroo pocket and adjustable drawstrings. Comfortable, durable, and timeless.", sizes: ["XS", "S", "M", "L", "XL", "XXL"],
colors: ["Black", "Charcoal", "Navy", "White"],
},
"2": {
name: "Vintage Denim Jacket", price: 129.99,
image: "http://img.b2bpic.net/free-photo/fashionable-woman-wearing-denim-jacket_23-2148859621.jpg", description: "Authentic vintage-inspired denim jacket with a modern fit. Featuring button closure, multiple pockets, and classic denim construction. A versatile staple for any wardrobe.", sizes: ["XS", "S", "M", "L", "XL"],
colors: ["Indigo", "Light Blue", "Black"],
},
"3": {
name: "Cargo Pants - Khaki", price: 79.99,
image: "http://img.b2bpic.net/free-photo/young-woman-wearing-trucker-hat_23-2149432334.jpg", description: "Comfortable cargo pants with multiple pockets and adjustable straps. Perfect for everyday wear with a practical, streetwear aesthetic. Premium cotton blend fabric.", sizes: ["XS", "S", "M", "L", "XL", "XXL"],
colors: ["Khaki", "Black", "Olive"],
},
};
export default function ProductPage({ params }: { params: { id: string } }) {
const product = productDetails[params.id as keyof typeof productDetails] || productDetails["1"];
) as any;
export default function ProductDetailPage() {
const navItems = [
{ name: "Shop", id: "products" },
{ name: "Collections", id: "collections" },
@@ -49,6 +30,28 @@ export default function ProductPage({ params }: { params: { id: string } }) {
{ name: "Contact", id: "contact" },
];
const [quantity, setQuantity] = useState(1);
const [isFavorite, setIsFavorite] = useState(false);
const [selectedSize, setSelectedSize] = useState("M");
const [selectedColor, setSelectedColor] = useState("Black");
const product = {
id: "1", name: "Classic Black Hoodie", price: 89.99,
originalPrice: 119.99,
rating: 4.8,
reviews: 128,
description: "Experience premium comfort with our Classic Black Hoodie. Crafted from high-quality materials, this versatile piece is perfect for any season. Features a spacious kangaroo pocket, drawstring hood, and relaxed fit that pairs well with any outfit.", images: [
"http://img.b2bpic.net/free-photo/medium-shot-man-posing-with-hoodie-indoors_23-2149359859.jpg", "http://img.b2bpic.net/free-photo/medium-shot-cool-man-with-electric-scooter_23-2149356776.jpg"],
sizes: ["XS", "S", "M", "L", "XL", "XXL"],
colors: ["Black", "Navy", "Gray", "Charcoal"],
specifications: [
{ label: "Material", value: "100% Premium Cotton" },
{ label: "Weight", value: "450 GSM" },
{ label: "Care", value: "Machine wash cold, tumble dry low" },
{ label: "Fit", value: "Relaxed fit" },
],
};
const socialLinks: Array<{ icon: LucideIcon; href: string; ariaLabel: string }> = [
{ icon: Instagram, href: "https://instagram.com/umbra", ariaLabel: "Instagram" },
{ icon: Twitter, href: "https://twitter.com/umbra", ariaLabel: "Twitter" },
@@ -56,6 +59,14 @@ export default function ProductPage({ params }: { params: { id: string } }) {
{ icon: Youtube, href: "https://youtube.com/@umbra", ariaLabel: "YouTube" },
];
const handleAddToCart = () => {
console.log(`Added ${quantity} of ${product.name} (${selectedSize}, ${selectedColor}) to cart`);
};
const handleToggleFavorite = () => {
setIsFavorite(!isFavorite);
};
return (
<ThemeProvider
defaultButtonVariant="shift-hover"
@@ -77,7 +88,7 @@ export default function ProductPage({ params }: { params: { id: string } }) {
/>
</div>
<div id="product" data-section="product" className="mx-auto px-4 md:px-6">
<div id="product-detail" data-section="product-detail" className="mx-auto px-4 md:px-6">
<div className="py-20">
<div className="max-w-6xl mx-auto">
<Link href="/shop" className="text-accent hover:text-background-accent mb-8 inline-block">
@@ -85,37 +96,65 @@ export default function ProductPage({ params }: { params: { id: string } }) {
</Link>
<div className="grid grid-cols-1 md:grid-cols-2 gap-12">
<div className="bg-card/30 rounded-soft overflow-hidden h-96 md:h-full">
<img src={product.image} alt={product.name} className="w-full h-full object-cover" />
{/* Product Images */}
<div>
<div className="bg-card border border-accent/20 rounded-soft p-4 mb-4">
<img
src={product.images[0]}
alt={product.name}
className="w-full h-auto rounded-soft object-cover"
/>
</div>
<div className="grid grid-cols-4 gap-4">
{product.images.map((img, idx) => (
<div
key={idx}
className="bg-card border border-accent/20 rounded-soft p-2 cursor-pointer hover:border-accent/50 transition-colors"
>
<img src={img} alt={`${product.name} ${idx + 1}`} className="w-full h-auto object-cover" />
</div>
))}
</div>
</div>
<div className="flex flex-col justify-center">
{/* Product Details */}
<div>
<h1 className="text-4xl font-bold text-foreground mb-4">{product.name}</h1>
<p className="text-2xl font-semibold text-background-accent mb-6">${product.price.toFixed(2)}</p>
<p className="text-foreground/80 text-lg mb-8 leading-relaxed">{product.description}</p>
<div className="mb-8">
<h3 className="text-lg font-semibold text-foreground mb-4">Colors</h3>
<div className="flex gap-3">
{product.colors.map((color) => (
<button
key={color}
className="px-4 py-2 border border-accent/30 rounded-soft text-foreground hover:border-background-accent transition-colors"
>
{color}
</button>
))}
</div>
<div className="flex items-center gap-4 mb-6">
<span className="text-3xl font-bold text-background-accent">${product.price}</span>
<span className="text-lg line-through text-foreground/50">${product.originalPrice}</span>
<span className="px-3 py-1 bg-background-accent/20 text-background-accent rounded-full text-sm font-semibold">
{Math.round(((product.originalPrice - product.price) / product.originalPrice) * 100)}% OFF
</span>
</div>
<div className="mb-8">
<h3 className="text-lg font-semibold text-foreground mb-4">Sizes</h3>
<div className="flex flex-wrap gap-3">
<div className="flex items-center gap-2 mb-8">
<div className="flex text-background-accent">
{[...Array(5)].map((_, i) => (
<span key={i}></span>
))}
</div>
<span className="text-foreground/70">
{product.rating} ({product.reviews} reviews)
</span>
</div>
<p className="text-foreground/80 mb-8">{product.description}</p>
{/* Size Selection */}
<div className="mb-6">
<label className="block text-sm font-semibold text-foreground mb-3">Size</label>
<div className="grid grid-cols-6 gap-2">
{product.sizes.map((size) => (
<button
key={size}
className="px-4 py-2 border border-accent/30 rounded-soft text-foreground hover:border-background-accent transition-colors"
onClick={() => setSelectedSize(size)}
className={`py-2 rounded-soft font-semibold transition-colors ${
selectedSize === size
? "bg-background-accent text-primary-cta-text"
: "bg-card border border-accent/20 text-foreground hover:border-accent/50"
}`}
>
{size}
</button>
@@ -123,13 +162,76 @@ export default function ProductPage({ params }: { params: { id: string } }) {
</div>
</div>
<button className="px-8 py-4 bg-background-accent text-primary-cta-text font-semibold rounded-soft hover:bg-primary-cta transition-colors w-full mb-4">
Add to Cart
</button>
{/* Color Selection */}
<div className="mb-8">
<label className="block text-sm font-semibold text-foreground mb-3">Color</label>
<div className="flex gap-3">
{product.colors.map((color) => (
<button
key={color}
onClick={() => setSelectedColor(color)}
className={`px-4 py-2 rounded-soft font-semibold transition-colors ${
selectedColor === color
? "bg-background-accent text-primary-cta-text"
: "bg-card border border-accent/20 text-foreground hover:border-accent/50"
}`}
>
{color}
</button>
))}
</div>
</div>
<button className="px-8 py-4 border border-accent/50 text-foreground font-semibold rounded-soft hover:bg-accent/10 transition-colors w-full">
Save for Later
</button>
{/* Quantity & Buttons */}
<div className="flex gap-4 mb-8">
<div className="flex items-center gap-3 bg-card border border-accent/20 rounded-soft p-2">
<button
onClick={() => setQuantity(Math.max(1, quantity - 1))}
className="p-2 hover:bg-accent/20 rounded transition-colors"
>
<Minus size={18} className="text-foreground" />
</button>
<span className="w-8 text-center text-foreground font-semibold">{quantity}</span>
<button
onClick={() => setQuantity(quantity + 1)}
className="p-2 hover:bg-accent/20 rounded transition-colors"
>
<Plus size={18} className="text-foreground" />
</button>
</div>
<button
onClick={handleAddToCart}
className="flex-1 px-6 py-3 bg-background-accent text-primary-cta-text font-semibold rounded-soft hover:bg-primary-cta transition-colors flex items-center justify-center gap-2"
>
<ShoppingCart size={20} />
Add to Cart
</button>
<button
onClick={handleToggleFavorite}
className={`px-6 py-3 rounded-soft font-semibold transition-colors ${
isFavorite
? "bg-background-accent/20 text-background-accent"
: "bg-card border border-accent/20 text-foreground hover:border-accent/50"
}`}
>
<Heart size={20} fill={isFavorite ? "currentColor" : "none"} />
</button>
</div>
{/* Specifications */}
<div className="bg-card/50 border border-accent/20 rounded-soft p-6">
<h3 className="text-lg font-semibold text-foreground mb-4">Specifications</h3>
<div className="space-y-3">
{product.specifications.map((spec, idx) => (
<div key={idx} className="flex justify-between">
<span className="text-foreground/70">{spec.label}</span>
<span className="font-semibold text-foreground">{spec.value}</span>
</div>
))}
</div>
</div>
</div>
</div>
</div>

View File

@@ -10,7 +10,7 @@ import Link from "next/link";
import { TrendingUp, Instagram, Twitter, Youtube } from "lucide-react";
import type { LucideIcon } from "lucide-react";
const TikTok = (props: React.SVGProps<SVGSVGElement>) => (
const TikTok = (props: React.SVGProps<SVGSVGElement>): LucideIcon => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
@@ -21,7 +21,7 @@ const TikTok = (props: React.SVGProps<SVGSVGElement>) => (
>
<path d="M19.59 6.69a4.83 4.83 0 0 1-3.77-4.25V2h-3.68v13.67a2.4 2.4 0 1 1-2.4-2.4c.34 0 .67.03 1 .09V9.41a7.12 7.12 0 0 0-1-.08C5.89 9.33 2 13.46 2 18.13s3.88 8.81 8.74 8.81c4.65 0 8.6-3.36 8.6-7.53 0-.13 0-.26 0-.39a5.5 5.5 0 0 0-.56-1.78h.09c4.87 0 8.82-3.37 8.82-7.53 0-4.16-3.96-7.53-8.82-7.53z"/>
</svg>
) as unknown as LucideIcon;
) as any;
export default function ShopPage() {
const navItems = [