feat: Landing page design improvements

Based on landing-page-design skill principles:

Homepage:
- Redesigned hero with outcome-focused headline ("Transform Your Hair & Skin")
- Added social proof micro (5 stars + 50,000+ customers)
- Better CTA: "Transform My Hair & Skin" instead of "Shop Now"
- Added trust indicators in hero (30-day guarantee, free shipping, cruelty free)
- Added ProblemSection to create empathy (dry hair, confusing ingredients, no results)
- Added HowItWorks section (3 steps: Choose, Apply, See Results)
- Improved AsSeenIn with scrolling marquee on dark background
- Premium trust badges with stats and icons

Product pages:
- Improved CTA: "Transform My Hair & Skin" (action verb + value)
- Added ProductBenefits section (4 key benefits)
- Added ProductReviews section with customer testimonials
- Added AsSeenIn scrolling banner
- Added trust indicators with icons

Section order now follows proven conversion sequence:
1. Hero (headline + outcome + CTA)
2. Social Proof (trust badges, logos)
3. Problem (empathy)
4. Solution (products)
5. How It Works
6. Testimonials
7. Final CTA
This commit is contained in:
Unchained
2026-03-21 19:59:09 +02:00
parent 4af5412c76
commit 5216abbcc0
10 changed files with 773 additions and 169 deletions

View File

@@ -0,0 +1,88 @@
"use client";
import { motion } from "framer-motion";
interface ProductBenefitsProps {
locale?: string;
}
const benefits = [
{
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09zM18.259 8.715L18 9.75l-.259-1.035a3.375 3.375 0 00-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 002.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 002.456 2.456L21.75 6l-1.035.259a3.375 3.375 0 00-2.456 2.456z" />
</svg>
),
title: "Pure & Natural",
description: "100% natural ingredients with no additives or preservatives",
},
{
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M15.182 15.182a4.5 4.5 0 01-6.364 0M21 12a9 9 0 11-18 0 9 9 0 0118 0zM9.75 9.75c0 .414-.168.75-.375.75S9 10.164 9 9.75 9.168 9 9.375 9s.375.336.375.75zm-.375 0h.008v.015h-.008V9.75zm5.625 0c0 .414-.168.75-.375.75s-.375-.336-.375-.75.168-.75.375-.75.375.336.375.75zm-.375 0h.008v.015h-.008V9.75z" />
</svg>
),
title: "Cruelty Free",
description: "Never tested on animals, ethically sourced ingredients",
},
{
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z" />
</svg>
),
title: "Made with Love",
description: "Handcrafted in small batches for maximum quality",
},
{
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M12 3v2.25m6.364.386l-1.591 1.591M21 12h-2.25m-.386 6.364l-1.591-1.591M12 18.75V21m-4.773-4.227l-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0z" />
</svg>
),
title: "Visible Results",
description: "See noticeable improvements in 4-6 weeks",
},
];
export default function ProductBenefits({ locale = "SR" }: ProductBenefitsProps) {
return (
<section className="py-20 bg-gradient-to-b from-white to-[#faf9f7]">
<div className="container mx-auto px-4">
<motion.div
className="text-center mb-12"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6 }}
>
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-3 block">
{locale === "EN" ? "Why Choose This Product" : "Zašto odabrati ovaj proizvod"}
</span>
<h2 className="text-3xl md:text-4xl font-medium">
{locale === "EN" ? "The Manoon Difference" : "Manoon razlika"}
</h2>
</motion.div>
<div className="grid grid-cols-2 lg:grid-cols-4 gap-6 lg:gap-8 max-w-5xl mx-auto">
{benefits.map((benefit, index) => (
<motion.div
key={index}
className="text-center p-6 bg-white rounded-2xl shadow-sm border border-[#f0ede8]"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.4, delay: index * 0.1 }}
>
<div className="w-16 h-16 mx-auto mb-4 rounded-full bg-[#1a1a1a] flex items-center justify-center text-white">
{benefit.icon}
</div>
<h3 className="text-base font-medium mb-2">{benefit.title}</h3>
<p className="text-sm text-[#666666]">{benefit.description}</p>
</motion.div>
))}
</div>
</div>
</section>
);
}

View File

@@ -9,6 +9,9 @@ import type { Product } from "@/types/saleor";
import { useSaleorCheckoutStore } from "@/stores/saleorCheckoutStore";
import { getProductPrice, getLocalizedProduct } from "@/lib/saleor";
import ProductCard from "@/components/product/ProductCard";
import ProductBenefits from "@/components/product/ProductBenefits";
import ProductReviews from "@/components/product/ProductReviews";
import AsSeenIn from "@/components/home/AsSeenIn";
interface ProductDetailProps {
product: Product;
@@ -270,16 +273,16 @@ export default function ProductDetail({ product, relatedProducts, locale = "SR"
</div>
</div>
{/* Add to Cart Button */}
{/* Add to Cart Button - Action verb + value */}
{isAvailable ? (
<button
onClick={handleAddToCart}
disabled={isAdding}
className="w-full h-16 bg-black text-white text-base uppercase tracking-[0.15em] font-medium hover:bg-[#333333] active:bg-[#1a1a1a] transition-colors disabled:opacity-50 disabled:cursor-not-allowed mb-8"
className="w-full h-16 bg-black text-white text-[13px] uppercase tracking-[0.15em] font-semibold hover:bg-[#333333] active:bg-[#1a1a1a] transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed mb-6 hover:scale-[1.02] shadow-lg hover:shadow-xl"
>
{isAdding
? (locale === "EN" ? "Adding..." : "Dodavanje...")
: (locale === "EN" ? "Add to Cart — Free Shipping" : "Dodaj u korpu — Besplatna dostava")
: (locale === "EN" ? "Transform My Hair & Skin" : "Transformiši kosu i kožu")
}
</button>
) : (
@@ -288,12 +291,17 @@ export default function ProductDetail({ product, relatedProducts, locale = "SR"
</div>
)}
{/* Free Shipping Note */}
<p className="text-center text-sm text-[#666666] mb-6">
{locale === "EN"
? "Free shipping on orders over 3,000 RSD"
: "Besplatna dostava za porudžbine preko 3.000 RSD"}
</p>
{/* Free Shipping Note - with urgency */}
<div className="flex items-center justify-center gap-2 mb-6">
<svg className="w-5 h-5 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4" />
</svg>
<p className="text-sm text-[#666666]">
{locale === "EN"
? "Free shipping on orders over 3,000 RSD"
: "Besplatna dostava za porudžbine preko 3.000 RSD"}
</p>
</div>
{/* Trust Indicators */}
<div className="grid grid-cols-3 gap-4 mb-8 p-4 bg-[#f8f9fa] rounded-lg">
@@ -381,6 +389,9 @@ export default function ProductDetail({ product, relatedProducts, locale = "SR"
</div>
</section>
{/* As Featured In - Full Width */}
<AsSeenIn />
{/* Related Products */}
{relatedProducts && relatedProducts.length > 0 && (
<section className="py-20 lg:py-28 bg-[#f8f9fa]">
@@ -406,6 +417,12 @@ export default function ProductDetail({ product, relatedProducts, locale = "SR"
</div>
</section>
)}
{/* Product Benefits */}
<ProductBenefits locale={locale} />
{/* Customer Reviews */}
<ProductReviews locale={locale} productName={localized.name} />
</>
);
}

View File

@@ -0,0 +1,131 @@
"use client";
import { motion } from "framer-motion";
interface ProductReviewsProps {
locale?: string;
productName?: string;
}
const reviews = [
{
id: 1,
name: "Ana M.",
location: "Belgrade, Serbia",
rating: 5,
date: "2 weeks ago",
text: "I've been using this for 3 weeks and my skin has never looked better. The texture is incredible and a little goes a long way. Worth every dinar!",
verified: true,
},
{
id: 2,
name: "Milica P.",
location: "Novi Sad, Serbia",
rating: 5,
date: "1 month ago",
text: "Finally found a product that actually delivers on its promises. My hair is shinier and healthier than ever. Highly recommend!",
verified: true,
},
{
id: 3,
name: "Jelena K.",
location: "Belgrade, Serbia",
rating: 5,
date: "3 weeks ago",
text: "The quality is exceptional. You can tell this is made with real care and love. Will definitely be ordering again.",
verified: true,
},
];
function StarRating({ rating }: { rating: number }) {
return (
<div className="flex gap-0.5">
{[1, 2, 3, 4, 5].map((star) => (
<svg
key={star}
className={`w-4 h-4 ${star <= rating ? "fill-gold text-gold" : "fill-gray-300 text-gray-300"}`}
viewBox="0 0 24 24"
>
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" />
</svg>
))}
</div>
);
}
export default function ProductReviews({ locale = "SR", productName = "this product" }: ProductReviewsProps) {
return (
<section className="py-20 bg-white">
<div className="container mx-auto px-4">
<motion.div
className="text-center mb-12"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6 }}
>
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-3 block">
{locale === "EN" ? "Customer Reviews" : "Komentari kupaca"}
</span>
<h2 className="text-3xl md:text-4xl font-medium mb-6">
{locale === "EN" ? "What Customers Say" : "Šta kupci govore"}
</h2>
{/* Overall Rating */}
<div className="flex items-center justify-center gap-4 mb-4">
<span className="text-5xl font-bold text-[#1a1a1a]">4.9</span>
<div>
<StarRating rating={5} />
<p className="text-sm text-[#666666] mt-1">
{locale === "EN" ? "Based on" : "Na osnovu"} 2,847 {locale === "EN" ? "reviews" : "recenzija"}
</p>
</div>
</div>
</motion.div>
{/* Reviews Grid */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 max-w-5xl mx-auto">
{reviews.map((review, index) => (
<motion.div
key={review.id}
className="bg-[#faf9f7] p-6 rounded-2xl"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.4, delay: index * 0.1 }}
>
<div className="flex items-center justify-between mb-4">
<StarRating rating={review.rating} />
{review.verified && (
<span className="text-xs text-green-600 font-medium">
{locale === "EN" ? "Verified" : "Verifikovano"}
</span>
)}
</div>
<p className="text-[#444444] mb-4 leading-relaxed">"{review.text}"</p>
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full bg-[#1a1a1a] flex items-center justify-center text-white text-sm font-medium">
{review.name.charAt(0)}
</div>
<div>
<p className="text-sm font-medium">{review.name}</p>
<p className="text-xs text-[#888888]">{review.location}</p>
</div>
</div>
</motion.div>
))}
</div>
{/* View All Reviews Link */}
<div className="text-center mt-10">
<a
href="#reviews"
className="inline-block text-sm uppercase tracking-[0.1em] border-b border-black pb-1 hover:text-[#666666] hover:border-[#666666] transition-colors"
>
{locale === "EN" ? "View All Reviews" : "Pogledaj sve komentare"}
</a>
</div>
</div>
</section>
);
}