feat: phase 1 - i18n core infrastructure with EN/DE/FR locales
- Add middleware.ts for locale detection (URL path, cookie, Accept-Language) - Update routing.ts to include en, de, fr locales - Update layout.tsx with NextIntlClientProvider and dynamic lang attribute - Create EN/DE/FR homepages, product listings, product details, about, and contact pages - Serbian remains at root URL (/products, /about, /contact) - English at /en/*, German at /de/*, French at /fr/*
This commit is contained in:
110
src/app/de/about/page.tsx
Normal file
110
src/app/de/about/page.tsx
Normal file
@@ -0,0 +1,110 @@
|
||||
import Header from "@/components/layout/Header";
|
||||
import Footer from "@/components/layout/Footer";
|
||||
|
||||
export const metadata = {
|
||||
title: "Über Uns - ManoonOils",
|
||||
description: "Erfahren Sie mehr über ManoonOils - unsere Geschichte, Mission und unser Engagement für natürliche Schönheit.",
|
||||
};
|
||||
|
||||
export default function AboutPage() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-white">
|
||||
<div className="pt-[104px]">
|
||||
<div className="container py-12 md:py-16">
|
||||
<div className="max-w-2xl mx-auto text-center">
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-3 block">Unsere Geschichte</span>
|
||||
<h1 className="text-4xl md:text-5xl font-medium tracking-tight">Über ManoonOils</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="relative h-[400px] md:h-[500px] overflow-hidden">
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?q=80&w=2000&auto=format&fit=crop"
|
||||
alt="Natürliche Ölproduktion"
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black/20" />
|
||||
</div>
|
||||
|
||||
<section className="py-16 md:py-24">
|
||||
<div className="container">
|
||||
<div className="max-w-3xl mx-auto">
|
||||
<div className="mb-16">
|
||||
<p className="text-xl md:text-2xl text-[#1a1a1a] leading-relaxed mb-8">
|
||||
ManoonOils wurde aus einer Leidenschaft für natürliche Schönheit und dem Glauben geboren,
|
||||
dass die beste Hautpflege von der Natur selbst kommt.
|
||||
</p>
|
||||
<p className="text-[#666666] leading-relaxed">
|
||||
Wir glauben an die Kraft natürlicher Inhaltsstoffe. Jedes Öl in unserer
|
||||
Kollektion wird sorgfältig aufgrund seiner einzigartigen Eigenschaften und
|
||||
Vorteile ausgewählt. Von nährenden Ölen, die die Haar vitalität wiederherstellen,
|
||||
bis zu Seren, die die Haut verjüngen, stellen wir jedes Produkt mit Liebe und
|
||||
Aufmerksamkeit für Details her.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-12 mb-16">
|
||||
<div className="p-6 bg-[#f8f9fa]">
|
||||
<h3 className="text-lg font-medium mb-3">Natürliche Inhaltsstoffe</h3>
|
||||
<p className="text-[#666666] text-sm leading-relaxed">
|
||||
Wir verwenden nur die feinsten natürlichen Inhaltsstoffe, die ethisch und nachhaltig
|
||||
von vertrauenswürdigen Lieferanten aus aller Welt bezogen werden.
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-6 bg-[#f8f9fa]">
|
||||
<h3 className="text-lg font-medium mb-3">Tierversuchsfrei</h3>
|
||||
<p className="text-[#666666] text-sm leading-relaxed">
|
||||
Unsere Produkte werden niemals an Tieren getestet. Wir glauben an Schönheit
|
||||
ohne Kompromisse.
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-6 bg-[#f8f9fa]">
|
||||
<h3 className="text-lg font-medium mb-3">Nachhaltige Verpackung</h3>
|
||||
<p className="text-[#666666] text-sm leading-relaxed">
|
||||
Wir verwenden umweltfreundliche Verpackungsmaterialien und minimieren Abfall
|
||||
während unseres gesamten Produktionsprozesses.
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-6 bg-[#f8f9fa]">
|
||||
<h3 className="text-lg font-medium mb-3">Handgefertigte Qualität</h3>
|
||||
<p className="text-[#666666] text-sm leading-relaxed">
|
||||
Jede Flasche wird in kleinen Chargen von Hand hergestellt, um
|
||||
höchste Qualität und Frische zu gewährleisten.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="text-center py-12 border-t border-b border-[#e5e5e5]">
|
||||
<span className="text-caption text-[#666666] mb-4 block">Unsere Mission</span>
|
||||
<blockquote className="text-2xl md:text-3xl font-medium tracking-tight">
|
||||
“Hochwertige, natürliche Produkte anzubieten, die Ihre tägliche Schönheitsroutine verbessern.”
|
||||
</blockquote>
|
||||
</div>
|
||||
|
||||
<div className="mt-16">
|
||||
<h2 className="text-2xl font-medium mb-6">Mit Liebe Handgemacht</h2>
|
||||
<p className="text-[#666666] leading-relaxed mb-6">
|
||||
Jede Flasche ManoonOils wird mit Sorgfalt von Hand hergestellt. Wir stellen unsere
|
||||
Produkte in kleinen Chargen her, um höchste Qualität und Frische zu gewährleisten.
|
||||
Wenn Sie ManoonOils verwenden, können Sie sicher sein, dass Sie etwas verwenden,
|
||||
das mit echter Sorgfalt und Fachwissen hergestellt wurde.
|
||||
</p>
|
||||
<p className="text-[#666666] leading-relaxed">
|
||||
Unsere Reise begann mit einer einfachen Frage: Wie können wir Produkte entwickeln,
|
||||
die Haar und Haut wirklich pflegen? Heute innovieren wir weiter, während wir
|
||||
unserem Engagement für natürliche, effektive Schönheitslösungen treu bleiben.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<div className="pt-16">
|
||||
<Footer />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
128
src/app/de/contact/page.tsx
Normal file
128
src/app/de/contact/page.tsx
Normal file
@@ -0,0 +1,128 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import Header from "@/components/layout/Header";
|
||||
import Footer from "@/components/layout/Footer";
|
||||
import { Mail, MapPin, Truck, Check } from "lucide-react";
|
||||
|
||||
export default function ContactPage() {
|
||||
const [formData, setFormData] = useState({ name: "", email: "", message: "" });
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setSubmitted(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-white">
|
||||
<div className="pt-[104px]">
|
||||
<div className="container py-12 md:py-16">
|
||||
<div className="max-w-2xl mx-auto text-center">
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-3 block">Kontaktieren Sie Uns</span>
|
||||
<h1 className="text-4xl md:text-5xl font-medium tracking-tight mb-4">Kontakt</h1>
|
||||
<p className="text-[#666666]">Haben Sie Fragen? Wir würden uns freuen, von Ihnen zu hören.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section className="py-12 md:py-16">
|
||||
<div className="container">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 lg:gap-20">
|
||||
<div>
|
||||
<h2 className="text-2xl font-medium mb-6">Kontaktieren Sie Uns</h2>
|
||||
<p className="text-[#666666] mb-8 leading-relaxed">
|
||||
Wir sind hier um zu helfen! Ob Sie Fragen zu unseren Produkten haben,
|
||||
Hilfe bei einer Bestellung benötigen oder einfach Hallo sagen möchten.
|
||||
</p>
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="w-12 h-12 rounded-full bg-[#f8f9fa] flex items-center justify-center flex-shrink-0">
|
||||
<Mail className="w-5 h-5 text-[#666666]" strokeWidth={1.5} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-medium mb-1">E-Mail</h3>
|
||||
<p className="text-[#666666] text-sm">hello@manoonoils.com</p>
|
||||
<p className="text-[#999999] text-xs mt-1">Wir antworten innerhalb von 24 Stunden</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="w-12 h-12 rounded-full bg-[#f8f9fa] flex items-center justify-center flex-shrink-0">
|
||||
<Truck className="w-5 h-5 text-[#666666]" strokeWidth={1.5} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-medium mb-1">Versand</h3>
|
||||
<p className="text-[#666666] text-sm">Kostenloser Versand ab €50</p>
|
||||
<p className="text-[#999999] text-xs mt-1">Lieferung innerhalb von 2-5 Werktagen</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="w-12 h-12 rounded-full bg-[#f8f9fa] flex items-center justify-center flex-shrink-0">
|
||||
<MapPin className="w-5 h-5 text-[#666666]" strokeWidth={1.5} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-medium mb-1">Standort</h3>
|
||||
<p className="text-[#666666] text-sm">Serbien</p>
|
||||
<p className="text-[#999999] text-xs mt-1">Weltweiter Versand</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-[#f8f9fa] p-8 md:p-10">
|
||||
{submitted ? (
|
||||
<div className="text-center py-12">
|
||||
<div className="w-16 h-16 rounded-full bg-green-100 flex items-center justify-center mx-auto mb-4">
|
||||
<Check className="w-8 h-8 text-green-600" strokeWidth={1.5} />
|
||||
</div>
|
||||
<h3 className="text-xl font-medium mb-2">Vielen Dank!</h3>
|
||||
<p className="text-[#666666]">Ihre Nachricht wurde gesendet. Wir werden uns bald bei Ihnen melden.</p>
|
||||
</div>
|
||||
) : (
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
<div>
|
||||
<label htmlFor="name" className="block text-sm font-medium mb-2">Name</label>
|
||||
<input type="text" id="name" required value={formData.name} onChange={(e) => setFormData({ ...formData, name: e.target.value })} className="w-full px-4 py-3 bg-white border border-[#e5e5e5] focus:outline-none focus:border-black transition-colors" placeholder="Ihr Name" />
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="email" className="block text-sm font-medium mb-2">E-Mail</label>
|
||||
<input type="email" id="email" required value={formData.email} onChange={(e) => setFormData({ ...formData, email: e.target.value })} className="w-full px-4 py-3 bg-white border border-[#e5e5e5] focus:outline-none focus:border-black transition-colors" placeholder="ihre@email.com" />
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="message" className="block text-sm font-medium mb-2">Nachricht</label>
|
||||
<textarea id="message" required rows={5} value={formData.message} onChange={(e) => setFormData({ ...formData, message: e.target.value })} className="w-full px-4 py-3 bg-white border border-[#e5e5e5] focus:outline-none focus:border-black transition-colors resize-none" placeholder="Wie können wir Ihnen helfen?" />
|
||||
</div>
|
||||
<button type="submit" className="w-full py-4 bg-black text-white text-sm uppercase tracking-[0.1em] font-medium hover:bg-[#333333] transition-colors">Nachricht Senden</button>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-16 md:py-24 border-t border-[#e5e5e5]">
|
||||
<div className="container">
|
||||
<div className="max-w-3xl mx-auto">
|
||||
<h2 className="text-2xl font-medium text-center mb-12">Häufig Gestellte Fragen</h2>
|
||||
<div className="space-y-6">
|
||||
{[
|
||||
{ q: "Wie lange dauert der Versand?", a: "Bestellungen werden normalerweise innerhalb von 2-5 Werktagen für Inlandsversand geliefert. Sie erhalten eine Tracking-Nummer, sobald Ihre Bestellung versandt wurde." },
|
||||
{ q: "Sind Ihre Produkte 100% natürlich?", a: "Ja! Alle unsere Öle sind 100% natürlich, kaltgepresst und frei von Zusatzstoffen, Konservierungsstoffen oder künstlichen Duftstoffen." },
|
||||
{ q: "Was ist Ihre Rückgaberichtlinie?", a: "Wir akzeptieren Rücksendungen innerhalb von 14 Tagen nach Lieferung für ungeöffnete Produkte. Bitte kontaktieren Sie uns, wenn Sie Probleme mit Ihrer Bestellung haben." },
|
||||
{ q: "Bieten Sie Wiederverkauf an?", a: "Ja, wir bieten Wiederverkaufspreise für Bulk-Bestellungen. Bitte kontaktieren Sie uns unter hello@manoonoils.com für mehr Informationen." }
|
||||
].map((faq, index) => (
|
||||
<div key={index} className="border-b border-[#e5e5e5] pb-6">
|
||||
<h3 className="font-medium mb-2">{faq.q}</h3>
|
||||
<p className="text-[#666666] text-sm leading-relaxed">{faq.a}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<div className="pt-16"><Footer /></div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
213
src/app/de/page.tsx
Normal file
213
src/app/de/page.tsx
Normal file
@@ -0,0 +1,213 @@
|
||||
import { getProducts } from "@/lib/saleor";
|
||||
import Header from "@/components/layout/Header";
|
||||
import Footer from "@/components/layout/Footer";
|
||||
import HeroVideo from "@/components/home/HeroVideo";
|
||||
import ProductCard from "@/components/product/ProductCard";
|
||||
import TrustBadges from "@/components/home/TrustBadges";
|
||||
import AsSeenIn from "@/components/home/AsSeenIn";
|
||||
import ProductReviews from "@/components/product/ProductReviews";
|
||||
import BeforeAfterGallery from "@/components/home/BeforeAfterGallery";
|
||||
import ProblemSection from "@/components/home/ProblemSection";
|
||||
import HowItWorks from "@/components/home/HowItWorks";
|
||||
|
||||
export const metadata = {
|
||||
title: "ManoonOils - Premium Natürliche Öle für Haar & Haut",
|
||||
description:
|
||||
"Entdecken Sie unsere Premium-Kollektion natürlicher Öle für Haar- und Hautpflege. Mit Liebe handgemacht aus den feinsten Zutaten.",
|
||||
};
|
||||
|
||||
export default async function GermanHomepage() {
|
||||
let products: any[] = [];
|
||||
try {
|
||||
products = await getProducts("DE");
|
||||
} catch (e) {
|
||||
console.log("Failed to fetch products during build");
|
||||
}
|
||||
|
||||
const featuredProducts = products?.slice(0, 4) || [];
|
||||
const hasProducts = featuredProducts.length > 0;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
|
||||
<main className="min-h-screen bg-white">
|
||||
<HeroVideo />
|
||||
|
||||
<AsSeenIn />
|
||||
|
||||
<ProductReviews />
|
||||
|
||||
<TrustBadges />
|
||||
|
||||
<ProblemSection />
|
||||
|
||||
<BeforeAfterGallery />
|
||||
|
||||
<div id="main_content" className="scroll-mt-[72px] lg:scroll-mt-[72px]">
|
||||
{hasProducts && (
|
||||
<section className="py-24 px-4 sm:px-6 lg:px-8 bg-white">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="text-center mb-16">
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-3 block">
|
||||
Unsere Kollektion
|
||||
</span>
|
||||
<h2 className="text-3xl md:text-4xl font-medium mb-4">
|
||||
Premium Natürliche Öle
|
||||
</h2>
|
||||
<p className="text-[#666666] max-w-xl mx-auto">
|
||||
Kaltgepresst, rein und natürlich für Ihre tägliche Schönheitsroutine
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 lg:gap-8">
|
||||
{featuredProducts.map((product, index) => (
|
||||
<ProductCard key={product.id} product={product} index={index} locale="DE" />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="text-center mt-12">
|
||||
<a
|
||||
href="/de/products"
|
||||
className="inline-block text-sm uppercase tracking-[0.1em] border-b border-black pb-1 hover:text-[#666666] hover:border-[#666666] transition-colors"
|
||||
>
|
||||
Alle Produkte Ansehen
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
<HowItWorks />
|
||||
|
||||
<section className="py-24 px-4 sm:px-6 lg:px-8 bg-[#f8f9fa]">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 lg:gap-20 items-center">
|
||||
<div>
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-3 block">
|
||||
Unsere Geschichte
|
||||
</span>
|
||||
<h2 className="text-3xl md:text-4xl font-medium mb-6">
|
||||
Mit Liebe Handgemacht
|
||||
</h2>
|
||||
<p className="text-[#666666] mb-6 leading-relaxed">
|
||||
Jede Flasche ManoonOils wird mit größter Sorgfalt hergestellt, unter
|
||||
Verwendung traditioneller Methoden, die von Generation zu Generation
|
||||
weitergegeben wurden. Wir beziehen nur die besten organischen
|
||||
Zutaten, um Ihnen Öle zu liefern, die Haar und Haut pflegen.
|
||||
</p>
|
||||
<p className="text-[#666666] mb-8 leading-relaxed">
|
||||
Unser Engagement für Reinheit bedeutet: keine Zusatzstoffe, keine
|
||||
Konservierungsstoffe - nur die Güte der Natur in ihrer potentesten Form.
|
||||
</p>
|
||||
<a
|
||||
href="/de/about"
|
||||
className="inline-block text-sm uppercase tracking-[0.1em] border-b border-black pb-1 hover:text-[#666666] hover:border-[#666666] transition-colors"
|
||||
>
|
||||
Mehr Erfahren
|
||||
</a>
|
||||
</div>
|
||||
<div className="relative aspect-[4/3] bg-[#e8f0f5] rounded-lg overflow-hidden">
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?q=80&w=800&auto=format&fit=crop"
|
||||
alt="Natürliche Ölproduktion"
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-24 px-4 sm:px-6 lg:px-8 bg-gradient-to-b from-white to-[#faf9f7]">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="text-center mb-16">
|
||||
<span className="text-xs uppercase tracking-[0.3em] text-[#c9a962] mb-4 block font-medium">
|
||||
Warum Uns Wählen
|
||||
</span>
|
||||
<h2 className="text-3xl md:text-4xl lg:text-5xl font-medium text-[#1a1a1a]">
|
||||
Der Manoon Unterschied
|
||||
</h2>
|
||||
<div className="w-24 h-1 bg-gradient-to-r from-[#c9a962] to-[#FFD700] mx-auto mt-6 rounded-full" />
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 lg:gap-8">
|
||||
{[
|
||||
{
|
||||
title: "100% Natürlich",
|
||||
description: "Reine, kaltgepresste Öle ohne Zusatzstoffe oder Konservierungsstoffe. Nur die Güte der Natur.",
|
||||
icon: (
|
||||
<svg className="w-10 h-10" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" fill="#7eb89e"/>
|
||||
<path stroke="#7eb89e" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Handgefertigt",
|
||||
description: "Jede Charge wird sorgfältig von Hand zubereitet, um höchste Qualität zu gewährleisten.",
|
||||
icon: (
|
||||
<svg className="w-10 h-10" viewBox="0 0 24 24" fill="none">
|
||||
<path stroke="#c9a962" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" 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: "Nachhaltig",
|
||||
description: "Ethnisch beschaffte Zutaten und umweltfreundliche Verpackungen für einen besseren Planeten.",
|
||||
icon: (
|
||||
<svg className="w-10 h-10" viewBox="0 0 24 24" fill="none">
|
||||
<path stroke="#e8967a" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" d="M12.75 3.03v.568c0 .334.148.65.405.864l1.068.89c.442.369.535 1.01.216 1.49l-.51.766a2.25 2.25 0 01-1.161.886l-.143.048a1.107 1.107 0 00-.57 1.664c.369.555.169 1.307-.427 1.605L9 13.125l.423 1.059a.956.956 0 11-1.652.928l-.714-.093a1.125 1.125 0 00-1.906.172L4.5 15.75l-.612.153M12.75 3.031l.002-.004m0 0a8.955 8.955 0 00-4.943.834 8.974 8.974 0 004.943.834m4.943-.834a8.955 8.955 0 00-4.943-.834c2.687 0 5.18.948 7.161 2.664a8.974 8.974 0 014.943-.834z"/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
].map((benefit, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="relative text-center p-8 bg-white rounded-3xl shadow-lg border border-[#f0ede8] hover:shadow-2xl hover:border-[#c9a962]/30 transition-all duration-500 group"
|
||||
>
|
||||
<div className="w-20 h-20 mx-auto mb-6 rounded-2xl bg-gradient-to-br from-[#faf9f7] to-[#f5f0e8] flex items-center justify-center shadow-md border border-[#e8e4dc] group-hover:border-[#c9a962]/50 transition-colors duration-300">
|
||||
{benefit.icon}
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold text-[#1a1a1a] mb-3">{benefit.title}</h3>
|
||||
<p className="text-sm text-[#666666] leading-relaxed">{benefit.description}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-28 lg:py-32 px-4 sm:px-6 lg:px-8 bg-[#1a1a1a] text-white">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="max-w-2xl mx-auto text-center">
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-white/60 mb-3 block">
|
||||
Verbunden Bleiben
|
||||
</span>
|
||||
<h2 className="text-3xl md:text-4xl lg:text-5xl font-medium mb-6">
|
||||
Werden Sie Teil Unserer Gemeinschaft
|
||||
</h2>
|
||||
<p className="text-white/70 mb-10 mx-auto text-lg">
|
||||
Abonnieren Sie, um exklusive Angebote, Beauty-Tipps zu erhalten und der Erste zu sein, der neue Produkte erfährt.
|
||||
</p>
|
||||
<form className="flex flex-col sm:flex-row items-stretch justify-center max-w-md mx-auto gap-0">
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Geben Sie Ihre E-Mail ein"
|
||||
className="flex-1 min-w-0 px-5 h-14 bg-white/10 border border-white/20 border-b-0 sm:border-b border-r-0 sm:border-r border-white/20 text-white placeholder:text-white/50 focus:border-white focus:outline-none transition-colors text-base text-center sm:text-left rounded-t sm:rounded-l sm:rounded-tr-none"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className="px-8 h-14 bg-white text-black text-sm uppercase tracking-[0.1em] font-medium hover:bg-white/90 transition-colors whitespace-nowrap flex-shrink-0 rounded-b sm:rounded-r sm:rounded-bl-none"
|
||||
>
|
||||
Abonnieren
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
}
|
||||
90
src/app/de/products/[slug]/page.tsx
Normal file
90
src/app/de/products/[slug]/page.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import { getProductBySlug, getProducts, getLocalizedProduct } from "@/lib/saleor";
|
||||
import Header from "@/components/layout/Header";
|
||||
import Footer from "@/components/layout/Footer";
|
||||
import ProductDetail from "@/components/product/ProductDetail";
|
||||
import type { Product } from "@/types/saleor";
|
||||
|
||||
interface ProductPageProps {
|
||||
params: Promise<{ slug: string }>;
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
try {
|
||||
const products = await getProducts("DE", 100);
|
||||
const params: Array<{ slug: string }> = [];
|
||||
products.forEach((product: Product) => {
|
||||
if (product.translation?.slug) {
|
||||
params.push({ slug: product.translation.slug });
|
||||
}
|
||||
});
|
||||
return params;
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: ProductPageProps) {
|
||||
const { slug } = await params;
|
||||
const product = await getProductBySlug(slug, "DE");
|
||||
|
||||
if (!product) {
|
||||
return { title: "Produkt Nicht Gefunden" };
|
||||
}
|
||||
|
||||
const localized = getLocalizedProduct(product, "DE");
|
||||
|
||||
return {
|
||||
title: localized.name,
|
||||
description: localized.seoDescription || localized.description?.slice(0, 160),
|
||||
openGraph: {
|
||||
title: localized.name,
|
||||
description: localized.seoDescription || localized.description?.slice(0, 160),
|
||||
images: product.media?.[0]?.url ? [product.media[0].url] : [],
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default async function GermanProductPage({ params }: ProductPageProps) {
|
||||
const { slug } = await params;
|
||||
const product = await getProductBySlug(slug, "DE");
|
||||
|
||||
if (!product) {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-white">
|
||||
<div className="pt-[180px] lg:pt-[200px] pb-20 text-center px-4">
|
||||
<h1 className="text-2xl font-medium mb-4">Produkt nicht gefunden</h1>
|
||||
<p className="text-[#666666] mb-8">
|
||||
Das gesuchte Produkt existiert nicht oder wurde entfernt.
|
||||
</p>
|
||||
<a
|
||||
href="/de/products"
|
||||
className="inline-block px-8 py-3 bg-black text-white text-sm uppercase tracking-[0.1em] hover:bg-[#333333] transition-colors"
|
||||
>
|
||||
Produkte Durchsuchen
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
let relatedProducts: Product[] = [];
|
||||
try {
|
||||
const allProducts = await getProducts("DE", 8);
|
||||
relatedProducts = allProducts.filter((p: Product) => p.id !== product.id).slice(0, 4);
|
||||
} catch (e) {}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-white">
|
||||
<ProductDetail product={product} relatedProducts={relatedProducts} locale="DE" />
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
}
|
||||
87
src/app/de/products/page.tsx
Normal file
87
src/app/de/products/page.tsx
Normal file
@@ -0,0 +1,87 @@
|
||||
import { getProducts } from "@/lib/saleor";
|
||||
import Header from "@/components/layout/Header";
|
||||
import Footer from "@/components/layout/Footer";
|
||||
import ProductCard from "@/components/product/ProductCard";
|
||||
import { ChevronDown } from "lucide-react";
|
||||
|
||||
export const metadata = {
|
||||
title: "Produkte - ManoonOils",
|
||||
description: "Durchsuchen Sie unsere Kollektion von Premium natürlichen Ölen für Haar- und Hautpflege.",
|
||||
};
|
||||
|
||||
export default async function GermanProductsPage() {
|
||||
const products = await getProducts("DE");
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
|
||||
<main className="min-h-screen bg-white">
|
||||
<div className="pt-[72px] lg:pt-[72px]">
|
||||
<div className="border-b border-[#e5e5e5]">
|
||||
<div className="container py-8 md:py-12">
|
||||
<div className="flex flex-col md:flex-row md:items-end md:justify-between gap-4">
|
||||
<div>
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-2 block">
|
||||
Unsere Kollektion
|
||||
</span>
|
||||
<h1 className="text-3xl md:text-4xl font-medium">
|
||||
Alle Produkte
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-sm text-[#666666]">
|
||||
{products.length} Produkte
|
||||
</span>
|
||||
<div className="relative">
|
||||
<select
|
||||
className="appearance-none bg-transparent border border-[#e5e5e5] pl-4 pr-10 py-2 text-sm focus:outline-none focus:border-black cursor-pointer"
|
||||
defaultValue="featured"
|
||||
>
|
||||
<option value="featured">Empfohlen</option>
|
||||
<option value="newest">Neueste</option>
|
||||
<option value="price-low">Preis: Aufsteigend</option>
|
||||
<option value="price-high">Preis: Absteigend</option>
|
||||
</select>
|
||||
<ChevronDown className="absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 pointer-events-none text-[#666666]" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section className="py-12 md:py-16">
|
||||
<div className="container">
|
||||
{products.length === 0 ? (
|
||||
<div className="text-center py-20">
|
||||
<p className="text-[#666666] mb-4">
|
||||
Keine Produkte verfügbar
|
||||
</p>
|
||||
<p className="text-sm text-[#999999]">
|
||||
Bitte schauen Sie später nach neuen Produkten.
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 lg:gap-8">
|
||||
{products.map((product, index) => (
|
||||
<ProductCard
|
||||
key={product.id}
|
||||
product={product}
|
||||
index={index}
|
||||
locale="DE"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div className="pt-16">
|
||||
<Footer />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,2 +1,113 @@
|
||||
// Re-export from main about page
|
||||
export { default, metadata } from "../../about/page";
|
||||
import Header from "@/components/layout/Header";
|
||||
import Footer from "@/components/layout/Footer";
|
||||
|
||||
export const metadata = {
|
||||
title: "About - ManoonOils",
|
||||
description: "Learn about ManoonOils - our story, mission, and commitment to natural beauty.",
|
||||
};
|
||||
|
||||
export default function AboutPage() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-white">
|
||||
<div className="pt-[104px]">
|
||||
<div className="container py-12 md:py-16">
|
||||
<div className="max-w-2xl mx-auto text-center">
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-3 block">Our Story</span>
|
||||
<h1 className="text-4xl md:text-5xl font-medium tracking-tight">
|
||||
About ManoonOils
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="relative h-[400px] md:h-[500px] overflow-hidden">
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?q=80&w=2000&auto=format&fit=crop"
|
||||
alt="Natural oils production"
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black/20" />
|
||||
</div>
|
||||
|
||||
<section className="py-16 md:py-24">
|
||||
<div className="container">
|
||||
<div className="max-w-3xl mx-auto">
|
||||
<div className="mb-16">
|
||||
<p className="text-xl md:text-2xl text-[#1a1a1a] leading-relaxed mb-8">
|
||||
ManoonOils was born from a passion for natural beauty and the belief
|
||||
that the best skincare comes from nature itself.
|
||||
</p>
|
||||
<p className="text-[#666666] leading-relaxed">
|
||||
We believe in the power of natural ingredients. Every oil in our
|
||||
collection is carefully selected for its unique properties and
|
||||
benefits. From nourishing oils that restore hair vitality to serums
|
||||
that rejuvenate skin, we craft each product with love and attention
|
||||
to detail.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-12 mb-16">
|
||||
<div className="p-6 bg-[#f8f9fa]">
|
||||
<h3 className="text-lg font-medium mb-3">Natural Ingredients</h3>
|
||||
<p className="text-[#666666] text-sm leading-relaxed">
|
||||
We use only the finest natural ingredients, sourced ethically and sustainably
|
||||
from trusted suppliers around the world.
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-6 bg-[#f8f9fa]">
|
||||
<h3 className="text-lg font-medium mb-3">Cruelty-Free</h3>
|
||||
<p className="text-[#666666] text-sm leading-relaxed">
|
||||
Our products are never tested on animals. We believe in beauty
|
||||
without compromise.
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-6 bg-[#f8f9fa]">
|
||||
<h3 className="text-lg font-medium mb-3">Sustainable Packaging</h3>
|
||||
<p className="text-[#666666] text-sm leading-relaxed">
|
||||
We use eco-friendly packaging materials and minimize waste
|
||||
throughout our production process.
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-6 bg-[#f8f9fa]">
|
||||
<h3 className="text-lg font-medium mb-3">Handcrafted Quality</h3>
|
||||
<p className="text-[#666666] text-sm leading-relaxed">
|
||||
Every bottle is handcrafted in small batches to ensure
|
||||
the highest quality and freshness.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="text-center py-12 border-t border-b border-[#e5e5e5]">
|
||||
<span className="text-caption text-[#666666] mb-4 block">Our Mission</span>
|
||||
<blockquote className="text-2xl md:text-3xl font-medium tracking-tight">
|
||||
“To provide premium quality, natural products that enhance
|
||||
your daily beauty routine.”
|
||||
</blockquote>
|
||||
</div>
|
||||
|
||||
<div className="mt-16">
|
||||
<h2 className="text-2xl font-medium mb-6">Handmade with Love</h2>
|
||||
<p className="text-[#666666] leading-relaxed mb-6">
|
||||
Every bottle of ManoonOils is handcrafted with care. We small-batch
|
||||
produce our products to ensure the highest quality and freshness.
|
||||
When you use ManoonOils, you can feel confident that you're using
|
||||
something made with genuine care and expertise.
|
||||
</p>
|
||||
<p className="text-[#666666] leading-relaxed">
|
||||
Our journey began with a simple question: how can we create products
|
||||
that truly nurture both hair and skin? Today, we continue to innovate
|
||||
while staying true to our commitment to natural, effective beauty solutions.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<div className="pt-16">
|
||||
<Footer />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { useState } from "react";
|
||||
import Header from "@/components/layout/Header";
|
||||
import Footer from "@/components/layout/Footer";
|
||||
import { Mail, MapPin, Truck, Check } from "lucide-react";
|
||||
|
||||
export default function ContactPage() {
|
||||
const [formData, setFormData] = useState({
|
||||
@@ -18,97 +19,180 @@ export default function ContactPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<main className="min-h-screen pt-16 md:pt-20">
|
||||
<>
|
||||
<Header />
|
||||
|
||||
<section className="py-20 px-4">
|
||||
<div className="max-w-2xl mx-auto">
|
||||
<h1 className="text-4xl md:text-5xl font-serif text-center mb-8">
|
||||
Contact Us
|
||||
</h1>
|
||||
|
||||
<p className="text-foreground-muted text-center mb-12">
|
||||
Have questions? We'd love to hear from you.
|
||||
</p>
|
||||
|
||||
{submitted ? (
|
||||
<div className="bg-green-50 text-green-700 p-6 text-center">
|
||||
<p className="text-lg">Thank you for your message!</p>
|
||||
<p className="mt-2">We'll get back to you soon.</p>
|
||||
</div>
|
||||
) : (
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
<div>
|
||||
<label htmlFor="name" className="block text-sm font-medium mb-2">
|
||||
Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
required
|
||||
value={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
className="w-full px-4 py-3 border border-border focus:outline-none focus:border-foreground"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="email" className="block text-sm font-medium mb-2">
|
||||
Email
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
required
|
||||
value={formData.email}
|
||||
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
|
||||
className="w-full px-4 py-3 border border-border focus:outline-none focus:border-foreground"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="message" className="block text-sm font-medium mb-2">
|
||||
Message
|
||||
</label>
|
||||
<textarea
|
||||
id="message"
|
||||
required
|
||||
rows={5}
|
||||
value={formData.message}
|
||||
onChange={(e) => setFormData({ ...formData, message: e.target.value })}
|
||||
className="w-full px-4 py-3 border border-border focus:outline-none focus:border-foreground resize-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full py-3 bg-foreground text-white hover:bg-accent-dark transition-colors"
|
||||
>
|
||||
Send Message
|
||||
</button>
|
||||
</form>
|
||||
)}
|
||||
|
||||
<div className="mt-16 pt-8 border-t border-border/30">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 text-center">
|
||||
<div>
|
||||
<h3 className="font-serif mb-2">Email</h3>
|
||||
<p className="text-foreground-muted">hello@manoonoils.com</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-serif mb-2">Shipping</h3>
|
||||
<p className="text-foreground-muted">Free over 3000 RSD</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-serif mb-2">Location</h3>
|
||||
<p className="text-foreground-muted">Serbia</p>
|
||||
</div>
|
||||
<main className="min-h-screen bg-white">
|
||||
<div className="pt-[104px]">
|
||||
<div className="container py-12 md:py-16">
|
||||
<div className="max-w-2xl mx-auto text-center">
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-3 block">Get in Touch</span>
|
||||
<h1 className="text-4xl md:text-5xl font-medium tracking-tight mb-4">
|
||||
Contact Us
|
||||
</h1>
|
||||
<p className="text-[#666666]">
|
||||
Have questions? We'd love to hear from you.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-12 md:py-16">
|
||||
<div className="container">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 lg:gap-20">
|
||||
<div>
|
||||
<h2 className="text-2xl font-medium mb-6">Get in Touch</h2>
|
||||
<p className="text-[#666666] mb-8 leading-relaxed">
|
||||
We're here to help! Whether you have questions about our products,
|
||||
need assistance with an order, or just want to say hello, we'd love to hear from you.
|
||||
</p>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="w-12 h-12 rounded-full bg-[#f8f9fa] flex items-center justify-center flex-shrink-0">
|
||||
<Mail className="w-5 h-5 text-[#666666]" strokeWidth={1.5} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-medium mb-1">Email</h3>
|
||||
<p className="text-[#666666] text-sm">hello@manoonoils.com</p>
|
||||
<p className="text-[#999999] text-xs mt-1">We reply within 24 hours</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="w-12 h-12 rounded-full bg-[#f8f9fa] flex items-center justify-center flex-shrink-0">
|
||||
<Truck className="w-5 h-5 text-[#666666]" strokeWidth={1.5} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-medium mb-1">Shipping</h3>
|
||||
<p className="text-[#666666] text-sm">Free shipping over £50</p>
|
||||
<p className="text-[#999999] text-xs mt-1">Delivered within 2-5 business days</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="w-12 h-12 rounded-full bg-[#f8f9fa] flex items-center justify-center flex-shrink-0">
|
||||
<MapPin className="w-5 h-5 text-[#666666]" strokeWidth={1.5} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-medium mb-1">Location</h3>
|
||||
<p className="text-[#666666] text-sm">Serbia</p>
|
||||
<p className="text-[#999999] text-xs mt-1">Shipping worldwide</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-[#f8f9fa] p-8 md:p-10">
|
||||
{submitted ? (
|
||||
<div className="text-center py-12">
|
||||
<div className="w-16 h-16 rounded-full bg-green-100 flex items-center justify-center mx-auto mb-4">
|
||||
<Check className="w-8 h-8 text-green-600" strokeWidth={1.5} />
|
||||
</div>
|
||||
<h3 className="text-xl font-medium mb-2">Thank You!</h3>
|
||||
<p className="text-[#666666]">
|
||||
Your message has been sent. We'll get back to you soon.
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
<div>
|
||||
<label htmlFor="name" className="block text-sm font-medium mb-2">
|
||||
Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
required
|
||||
value={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
className="w-full px-4 py-3 bg-white border border-[#e5e5e5] focus:outline-none focus:border-black transition-colors"
|
||||
placeholder="Your name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="email" className="block text-sm font-medium mb-2">
|
||||
Email
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
required
|
||||
value={formData.email}
|
||||
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
|
||||
className="w-full px-4 py-3 bg-white border border-[#e5e5e5] focus:outline-none focus:border-black transition-colors"
|
||||
placeholder="your@email.com"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="message" className="block text-sm font-medium mb-2">
|
||||
Message
|
||||
</label>
|
||||
<textarea
|
||||
id="message"
|
||||
required
|
||||
rows={5}
|
||||
value={formData.message}
|
||||
onChange={(e) => setFormData({ ...formData, message: e.target.value })}
|
||||
className="w-full px-4 py-3 bg-white border border-[#e5e5e5] focus:outline-none focus:border-black transition-colors resize-none"
|
||||
placeholder="How can we help you?"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full py-4 bg-black text-white text-sm uppercase tracking-[0.1em] font-medium hover:bg-[#333333] transition-colors"
|
||||
>
|
||||
Send Message
|
||||
</button>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-16 md:py-24 border-t border-[#e5e5e5]">
|
||||
<div className="container">
|
||||
<div className="max-w-3xl mx-auto">
|
||||
<h2 className="text-2xl font-medium text-center mb-12">
|
||||
Frequently Asked Questions
|
||||
</h2>
|
||||
|
||||
<div className="space-y-6">
|
||||
{[
|
||||
{
|
||||
q: "How long does shipping take?",
|
||||
a: "Orders are typically delivered within 2-5 business days for domestic shipping. You'll receive a tracking number once your order ships."
|
||||
},
|
||||
{
|
||||
q: "Are your products 100% natural?",
|
||||
a: "Yes! All our oils are 100% natural, cold-pressed, and free from any additives, preservatives, or artificial fragrances."
|
||||
},
|
||||
{
|
||||
q: "What is your return policy?",
|
||||
a: "We accept returns within 14 days of delivery for unopened products. Please contact us if you have any issues with your order."
|
||||
},
|
||||
{
|
||||
q: "Do you offer wholesale?",
|
||||
a: "Yes, we offer wholesale pricing for bulk orders. Please contact us at hello@manoonoils.com for more information."
|
||||
}
|
||||
].map((faq, index) => (
|
||||
<div key={index} className="border-b border-[#e5e5e5] pb-6">
|
||||
<h3 className="font-medium mb-2">{faq.q}</h3>
|
||||
<p className="text-[#666666] text-sm leading-relaxed">{faq.a}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</main>
|
||||
<div className="pt-16">
|
||||
<Footer />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,12 @@ import Header from "@/components/layout/Header";
|
||||
import Footer from "@/components/layout/Footer";
|
||||
import HeroVideo from "@/components/home/HeroVideo";
|
||||
import ProductCard from "@/components/product/ProductCard";
|
||||
import TrustBadges from "@/components/home/TrustBadges";
|
||||
import AsSeenIn from "@/components/home/AsSeenIn";
|
||||
import ProductReviews from "@/components/product/ProductReviews";
|
||||
import BeforeAfterGallery from "@/components/home/BeforeAfterGallery";
|
||||
import ProblemSection from "@/components/home/ProblemSection";
|
||||
import HowItWorks from "@/components/home/HowItWorks";
|
||||
|
||||
export const metadata = {
|
||||
title: "ManoonOils - Premium Natural Oils for Hair & Skin",
|
||||
@@ -10,47 +16,56 @@ export const metadata = {
|
||||
"Discover our premium collection of natural oils for hair and skin care. Handmade with love using only the finest ingredients.",
|
||||
};
|
||||
|
||||
export default async function Homepage() {
|
||||
export default async function EnglishHomepage() {
|
||||
let products: any[] = [];
|
||||
try {
|
||||
products = await getProducts("EN");
|
||||
products = await getProducts("UK");
|
||||
} catch (e) {
|
||||
console.log('Failed to fetch products during build');
|
||||
console.log("Failed to fetch products during build");
|
||||
}
|
||||
|
||||
const featuredProducts = products.slice(0, 4);
|
||||
|
||||
const featuredProducts = products?.slice(0, 4) || [];
|
||||
const hasProducts = featuredProducts.length > 0;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
|
||||
|
||||
<main className="min-h-screen bg-white">
|
||||
{/* Hero Section with Video Background */}
|
||||
<HeroVideo />
|
||||
|
||||
{/* Main Content */}
|
||||
<div id="main-content">
|
||||
{/* Products Grid Section */}
|
||||
{featuredProducts.length > 0 && (
|
||||
<AsSeenIn />
|
||||
|
||||
<ProductReviews />
|
||||
|
||||
<TrustBadges />
|
||||
|
||||
<ProblemSection />
|
||||
|
||||
<BeforeAfterGallery />
|
||||
|
||||
<div id="main_content" className="scroll-mt-[72px] lg:scroll-mt-[72px]">
|
||||
{hasProducts && (
|
||||
<section className="py-24 px-4 sm:px-6 lg:px-8 bg-white">
|
||||
<div className="container">
|
||||
{/* Section Header */}
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="text-center mb-16">
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-3 block">Our Collection</span>
|
||||
<h2 className="text-3xl md:text-4xl font-medium mb-4">Premium Natural Oils</h2>
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-3 block">
|
||||
Our Collection
|
||||
</span>
|
||||
<h2 className="text-3xl md:text-4xl font-medium mb-4">
|
||||
Premium Natural Oils
|
||||
</h2>
|
||||
<p className="text-[#666666] max-w-xl mx-auto">
|
||||
Cold-pressed, pure, and natural oils for your daily beauty routine
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Products Grid */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 lg:gap-8">
|
||||
{featuredProducts.map((product, index) => (
|
||||
<ProductCard key={product.id} product={product} index={index} locale="EN" />
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* View All Link */}
|
||||
<div className="text-center mt-12">
|
||||
<a
|
||||
href="/en/products"
|
||||
@@ -63,20 +78,25 @@ export default async function Homepage() {
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Brand Story Section */}
|
||||
<HowItWorks />
|
||||
|
||||
<section className="py-24 px-4 sm:px-6 lg:px-8 bg-[#f8f9fa]">
|
||||
<div className="container">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 lg:gap-20 items-center">
|
||||
<div>
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-3 block">Our Story</span>
|
||||
<h2 className="text-3xl md:text-4xl font-medium mb-6">Handmade with Love</h2>
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-3 block">
|
||||
Our Story
|
||||
</span>
|
||||
<h2 className="text-3xl md:text-4xl font-medium mb-6">
|
||||
Handmade with Love
|
||||
</h2>
|
||||
<p className="text-[#666666] mb-6 leading-relaxed">
|
||||
Every bottle of ManoonOils is crafted with care using traditional
|
||||
methods passed down through generations. We source only the finest
|
||||
Every bottle of ManoonOils is crafted with care using traditional
|
||||
methods passed down through generations. We source only the finest
|
||||
organic ingredients to bring you oils that nourish both hair and skin.
|
||||
</p>
|
||||
<p className="text-[#666666] mb-8 leading-relaxed">
|
||||
Our commitment to purity means no additives, no preservatives -
|
||||
Our commitment to purity means no additives, no preservatives -
|
||||
just nature's goodness in its most potent form.
|
||||
</p>
|
||||
<a
|
||||
@@ -97,76 +117,96 @@ export default async function Homepage() {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Benefits Section */}
|
||||
<section className="py-24 px-4 sm:px-6 lg:px-8 bg-white">
|
||||
<div className="container">
|
||||
<section className="py-24 px-4 sm:px-6 lg:px-8 bg-gradient-to-b from-white to-[#faf9f7]">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="text-center mb-16">
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-3 block">Why Choose Us</span>
|
||||
<h2 className="text-3xl md:text-4xl font-medium">The Manoon Difference</h2>
|
||||
<span className="text-xs uppercase tracking-[0.3em] text-[#c9a962] mb-4 block font-medium">
|
||||
Why Choose Us
|
||||
</span>
|
||||
<h2 className="text-3xl md:text-4xl lg:text-5xl font-medium text-[#1a1a1a]">
|
||||
The Manoon Difference
|
||||
</h2>
|
||||
<div className="w-24 h-1 bg-gradient-to-r from-[#c9a962] to-[#FFD700] mx-auto mt-6 rounded-full" />
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 lg:gap-12">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 lg:gap-8">
|
||||
{[
|
||||
{
|
||||
title: "100% Natural",
|
||||
description: "Pure, cold-pressed oils with no additives or preservatives. Just nature's goodness.",
|
||||
icon: (
|
||||
<svg className="w-10 h-10" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" fill="#7eb89e"/>
|
||||
<path stroke="#7eb89e" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Handcrafted",
|
||||
description: "Each batch is carefully prepared by hand to ensure the highest quality.",
|
||||
icon: (
|
||||
<svg className="w-10 h-10" viewBox="0 0 24 24" fill="none">
|
||||
<path stroke="#c9a962" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" 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: "Sustainable",
|
||||
description: "Ethically sourced ingredients and eco-friendly packaging for a better planet.",
|
||||
icon: (
|
||||
<svg className="w-10 h-10" viewBox="0 0 24 24" fill="none">
|
||||
<path stroke="#e8967a" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" d="M12.75 3.03v.568c0 .334.148.65.405.864l1.068.89c.442.369.535 1.01.216 1.49l-.51.766a2.25 2.25 0 01-1.161.886l-.143.048a1.107 1.107 0 00-.57 1.664c.369.555.169 1.307-.427 1.605L9 13.125l.423 1.059a.956.956 0 11-1.652.928l-.714-.093a1.125 1.125 0 00-1.906.172L4.5 15.75l-.612.153M12.75 3.031l.002-.004m0 0a8.955 8.955 0 00-4.943.834 8.974 8.974 0 004.943.834m4.943-.834a8.955 8.955 0 00-4.943-.834c2.687 0 5.18.948 7.161 2.664a8.974 8.974 0 014.943-.834z"/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
].map((benefit, index) => (
|
||||
<div key={index} className="text-center">
|
||||
<div className="w-16 h-16 mx-auto mb-6 rounded-full bg-[#e8f0f5] flex items-center justify-center">
|
||||
<span className="text-2xl font-medium text-[#1a1a1a]">
|
||||
{String(index + 1).padStart(2, '0')}
|
||||
</span>
|
||||
<div
|
||||
key={index}
|
||||
className="relative text-center p-8 bg-white rounded-3xl shadow-lg border border-[#f0ede8] hover:shadow-2xl hover:border-[#c9a962]/30 transition-all duration-500 group"
|
||||
>
|
||||
<div className="w-20 h-20 mx-auto mb-6 rounded-2xl bg-gradient-to-br from-[#faf9f7] to-[#f5f0e8] flex items-center justify-center shadow-md border border-[#e8e4dc] group-hover:border-[#c9a962]/50 transition-colors duration-300">
|
||||
{benefit.icon}
|
||||
</div>
|
||||
<h3 className="text-xl font-medium mb-3">{benefit.title}</h3>
|
||||
<p className="text-[#666666]">{benefit.description}</p>
|
||||
<h3 className="text-xl font-semibold text-[#1a1a1a] mb-3">{benefit.title}</h3>
|
||||
<p className="text-sm text-[#666666] leading-relaxed">{benefit.description}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Newsletter Section */}
|
||||
<section className="py-28 lg:py-32 px-4 sm:px-6 lg:px-8 bg-[#1a1a1a] text-white mb-16">
|
||||
<div className="container">
|
||||
<section className="py-28 lg:py-32 px-4 sm:px-6 lg:px-8 bg-[#1a1a1a] text-white">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="max-w-2xl mx-auto text-center">
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-white/60 mb-3 block">Stay Connected</span>
|
||||
<h2 className="text-3xl md:text-4xl lg:text-5xl font-medium mb-6">Join Our Community</h2>
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-white/60 mb-3 block">
|
||||
Stay Connected
|
||||
</span>
|
||||
<h2 className="text-3xl md:text-4xl lg:text-5xl font-medium mb-6">
|
||||
Join Our Community
|
||||
</h2>
|
||||
<p className="text-white/70 mb-10 mx-auto text-lg">
|
||||
Subscribe to receive exclusive offers, beauty tips, and be the first to know about new products.
|
||||
</p>
|
||||
<div className="flex justify-center">
|
||||
<form className="inline-flex flex-col sm:flex-row">
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Enter your email"
|
||||
className="w-64 sm:w-80 px-5 h-14 bg-white/10 border border-white/20 text-white placeholder:text-white/50 focus:border-white focus:outline-none transition-colors text-base text-center sm:text-left"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className="px-8 h-14 bg-white text-black text-sm uppercase tracking-[0.1em] font-medium hover:bg-white/90 transition-colors whitespace-nowrap"
|
||||
>
|
||||
Subscribe
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<form className="flex flex-col sm:flex-row items-stretch justify-center max-w-md mx-auto gap-0">
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Enter your email"
|
||||
className="flex-1 min-w-0 px-5 h-14 bg-white/10 border border-white/20 border-b-0 sm:border-b border-r-0 sm:border-r border-white/20 text-white placeholder:text-white/50 focus:border-white focus:outline-none transition-colors text-base text-center sm:text-left rounded-t sm:rounded-l sm:rounded-tr-none"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className="px-8 h-14 bg-white text-black text-sm uppercase tracking-[0.1em] font-medium hover:bg-white/90 transition-colors whitespace-nowrap flex-shrink-0 rounded-b sm:rounded-r sm:rounded-bl-none"
|
||||
>
|
||||
Subscribe
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div className="pt-16">
|
||||
<Footer />
|
||||
</div>
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,24 +3,19 @@ import Header from "@/components/layout/Header";
|
||||
import Footer from "@/components/layout/Footer";
|
||||
import ProductDetail from "@/components/product/ProductDetail";
|
||||
import type { Product } from "@/types/saleor";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
interface ProductPageProps {
|
||||
params: Promise<{ slug: string }>;
|
||||
}
|
||||
|
||||
// Generate static params for all products
|
||||
export async function generateStaticParams() {
|
||||
try {
|
||||
const products = await getProducts("EN", 100);
|
||||
const products = await getProducts("UK", 100);
|
||||
const params: Array<{ slug: string }> = [];
|
||||
|
||||
products.forEach((product: Product) => {
|
||||
// English slug (if translation exists)
|
||||
if (product.translation?.slug) {
|
||||
params.push({ slug: product.translation.slug });
|
||||
} else {
|
||||
params.push({ slug: product.slug });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -30,7 +25,7 @@ export async function generateStaticParams() {
|
||||
}
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: ProductPageProps): Promise<Metadata> {
|
||||
export async function generateMetadata({ params }: ProductPageProps) {
|
||||
const { slug } = await params;
|
||||
const product = await getProductBySlug(slug, "EN");
|
||||
|
||||
@@ -45,35 +40,42 @@ export async function generateMetadata({ params }: ProductPageProps): Promise<Me
|
||||
return {
|
||||
title: localized.name,
|
||||
description: localized.seoDescription || localized.description?.slice(0, 160),
|
||||
openGraph: {
|
||||
title: localized.name,
|
||||
description: localized.seoDescription || localized.description?.slice(0, 160),
|
||||
images: product.media?.[0]?.url ? [product.media[0].url] : [],
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default async function ProductPage({ params }: ProductPageProps) {
|
||||
export default async function EnglishProductPage({ params }: ProductPageProps) {
|
||||
const { slug } = await params;
|
||||
const product = await getProductBySlug(slug, "EN");
|
||||
|
||||
if (!product) {
|
||||
return (
|
||||
<main className="min-h-screen bg-white">
|
||||
<>
|
||||
<Header />
|
||||
<div className="pt-[120px] text-center px-4">
|
||||
<h1 className="text-2xl font-medium mb-4">Product not found</h1>
|
||||
<p className="text-[#666666] mb-8">
|
||||
The product you're looking for doesn't exist or has been removed.
|
||||
</p>
|
||||
<a
|
||||
href="/products"
|
||||
className="inline-block px-8 py-3 bg-black text-white text-sm uppercase tracking-[0.1em] hover:bg-[#333333] transition-colors"
|
||||
>
|
||||
Browse Products
|
||||
</a>
|
||||
</div>
|
||||
<main className="min-h-screen bg-white">
|
||||
<div className="pt-[180px] lg:pt-[200px] pb-20 text-center px-4">
|
||||
<h1 className="text-2xl font-medium mb-4">Product not found</h1>
|
||||
<p className="text-[#666666] mb-8">
|
||||
The product you're looking for doesn't exist or has been removed.
|
||||
</p>
|
||||
<a
|
||||
href="/en/products"
|
||||
className="inline-block px-8 py-3 bg-black text-white text-sm uppercase tracking-[0.1em] hover:bg-[#333333] transition-colors"
|
||||
>
|
||||
Browse Products
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// Get related products
|
||||
let relatedProducts: Product[] = [];
|
||||
try {
|
||||
const allProducts = await getProducts("EN", 8);
|
||||
@@ -85,14 +87,16 @@ export default async function ProductPage({ params }: ProductPageProps) {
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="min-h-screen bg-white">
|
||||
<>
|
||||
<Header />
|
||||
<ProductDetail
|
||||
product={product}
|
||||
relatedProducts={relatedProducts}
|
||||
locale="EN"
|
||||
/>
|
||||
<main className="min-h-screen bg-white">
|
||||
<ProductDetail
|
||||
product={product}
|
||||
relatedProducts={relatedProducts}
|
||||
locale="EN"
|
||||
/>
|
||||
</main>
|
||||
<Footer />
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,27 +9,31 @@ export const metadata = {
|
||||
description: "Browse our collection of premium natural oils for hair and skin care.",
|
||||
};
|
||||
|
||||
export default async function ProductsPage() {
|
||||
const products = await getProducts("EN");
|
||||
export default async function EnglishProductsPage() {
|
||||
const products = await getProducts("UK");
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
|
||||
<main className="min-h-screen bg-white">
|
||||
{/* Page Header */}
|
||||
<div className="pt-[104px]">
|
||||
<div className="pt-[72px] lg:pt-[72px]">
|
||||
<div className="border-b border-[#e5e5e5]">
|
||||
<div className="container py-8 md:py-12">
|
||||
<div className="flex flex-col md:flex-row md:items-end md:justify-between gap-4">
|
||||
<div>
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-2 block">Our Collection</span>
|
||||
<h1 className="text-3xl md:text-4xl font-medium">All Products</h1>
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-2 block">
|
||||
Our Collection
|
||||
</span>
|
||||
<h1 className="text-3xl md:text-4xl font-medium">
|
||||
All Products
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
{/* Sort Dropdown */}
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-sm text-[#666666]">{products.length} products</span>
|
||||
<span className="text-sm text-[#666666]">
|
||||
{products.length} products
|
||||
</span>
|
||||
<div className="relative">
|
||||
<select
|
||||
className="appearance-none bg-transparent border border-[#e5e5e5] pl-4 pr-10 py-2 text-sm focus:outline-none focus:border-black cursor-pointer"
|
||||
@@ -47,13 +51,16 @@ export default async function ProductsPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Products Grid */}
|
||||
<section className="py-12 md:py-16">
|
||||
<div className="container">
|
||||
{products.length === 0 ? (
|
||||
<div className="text-center py-20">
|
||||
<p className="text-[#666666] mb-4">No products available</p>
|
||||
<p className="text-sm text-[#999999]">Please check back later for new arrivals.</p>
|
||||
<p className="text-[#666666] mb-4">
|
||||
No products available
|
||||
</p>
|
||||
<p className="text-sm text-[#999999]">
|
||||
Please check back later for new arrivals.
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 lg:gap-8">
|
||||
|
||||
48
src/app/fr/about/page.tsx
Normal file
48
src/app/fr/about/page.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import Header from "@/components/layout/Header";
|
||||
import Footer from "@/components/layout/Footer";
|
||||
|
||||
export const metadata = {
|
||||
title: "À Propos - ManoonOils",
|
||||
description: "Découvrez ManoonOils - notre histoire, notre mission et notre engagement pour la beauté naturelle.",
|
||||
};
|
||||
|
||||
export default function AboutPage() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-white">
|
||||
<div className="pt-[104px]">
|
||||
<div className="container py-12 md:py-16">
|
||||
<div className="max-w-2xl mx-auto text-center">
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-3 block">Notre Histoire</span>
|
||||
<h1 className="text-4xl md:text-5xl font-medium tracking-tight">À Propos de ManoonOils</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative h-[400px] md:h-[500px] overflow-hidden">
|
||||
<img src="https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?q=80&w=2000&auto=format&fit=crop" alt="Production d'huiles naturelles" className="w-full h-full object-cover" />
|
||||
<div className="absolute inset-0 bg-black/20" />
|
||||
</div>
|
||||
<section className="py-16 md:py-24">
|
||||
<div className="container">
|
||||
<div className="max-w-3xl mx-auto">
|
||||
<div className="mb-16">
|
||||
<p className="text-xl md:text-2xl text-[#1a1a1a] leading-relaxed mb-8">ManoonOils est né d'une passion pour la beauté naturelle et de la conviction que les meilleurs soins Cutanee viennent de la nature elle-même.</p>
|
||||
<p className="text-[#666666] leading-relaxed">Nous croyons en le pouvoir des ingrédients naturels. Chaque huile de notre collection est soigneusement sélectionnée pour ses propriétés et bienfaits uniques. Des huiles nourrissantes qui restaurent la vitalité des cheveux aux sérums qui rajeunissent la peau, nous élaborons chaque produit avec amour et attention aux détails.</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-12 mb-16">
|
||||
<div className="p-6 bg-[#f8f9fa]"><h3 className="text-lg font-medium mb-3">Ingrédients Naturels</h3><p className="text-[#666666] text-sm leading-relaxed">Nous utilisons uniquement les meilleurs ingrédients naturels, sourcés de manière éthique et durable auprès de fournisseurs de confiance du monde entier.</p></div>
|
||||
<div className="p-6 bg-[#f8f9fa]"><h3 className="text-lg font-medium mb-3">Non Testé sur Animaux</h3><p className="text-[#666666] text-sm leading-relaxed">Nos produits ne sont jamais testés sur les animaux. Nous croyons en la beauté sans compromis.</p></div>
|
||||
<div className="p-6 bg-[#f8f9fa]"><h3 className="text-lg font-medium mb-3">Emballage Durable</h3><p className="text-[#666666] text-sm leading-relaxed">Nous utilisons des matériaux d'emballage écologiques et minimisons les déchets tout au long de notre processus de production.</p></div>
|
||||
<div className="p-6 bg-[#f8f9fa]"><h3 className="text-lg font-medium mb-3">Qualité Artisanale</h3><p className="text-[#666666] text-sm leading-relaxed">Chaque flacon est fabriqué à la main en petites quantités pour garantir la plus haute qualité et fraîcheur.</p></div>
|
||||
</div>
|
||||
<div className="text-center py-12 border-t border-b border-[#e5e5e5]"><span className="text-caption text-[#666666] mb-4 block">Notre Mission</span><blockquote className="text-2xl md:text-3xl font-medium tracking-tight">“Fournir des produits naturels de qualité premium qui améliorent votre routine beauté quotidienne.”</blockquote></div>
|
||||
<div className="mt-16"><h2 className="text-2xl font-medium mb-6">Fait Main avec Amour</h2><p className="text-[#666666] leading-relaxed mb-6">Chaque flacon de ManoonOils est fabriqué avec soin. Nous produisons nos produits en petites quantités pour garantir la plus haute qualité et fraîcheur. Lorsque vous utilisez ManoonOils, vous pouvez être sûr d'utiliser quelque chose fait avec un véritable soin et expertise.</p><p className="text-[#666666] leading-relaxed">Notre voyage a commencé par une simple question: comment créer des produits qui soignent vraiment les cheveux et la peau? Aujourd'hui, nous continuons à innover tout en restant fidèles à notre engagement envers des solutions beauté naturelles et efficaces.</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<div className="pt-16"><Footer /></div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
89
src/app/fr/contact/page.tsx
Normal file
89
src/app/fr/contact/page.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import Header from "@/components/layout/Header";
|
||||
import Footer from "@/components/layout/Footer";
|
||||
import { Mail, MapPin, Truck, Check } from "lucide-react";
|
||||
|
||||
export default function ContactPage() {
|
||||
const [formData, setFormData] = useState({ name: "", email: "", message: "" });
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setSubmitted(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-white">
|
||||
<div className="pt-[104px]">
|
||||
<div className="container py-12 md:py-16">
|
||||
<div className="max-w-2xl mx-auto text-center">
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-3 block">Contactez-Nous</span>
|
||||
<h1 className="text-4xl md:text-5xl font-medium tracking-tight mb-4">Nous Contacter</h1>
|
||||
<p className="text-[#666666]">Des questions? Nous serions ravis de vous entendre.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<section className="py-12 md:py-16">
|
||||
<div className="container">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 lg:gap-20">
|
||||
<div>
|
||||
<h2 className="text-2xl font-medium mb-6">Contactez-Nous</h2>
|
||||
<p className="text-[#666666] mb-8 leading-relaxed">Nous sommes là pour aider! Que vous ayez des questions sur nos produits, besoin d'aide avec une commande, ou simplement voulez dire bonjour.</p>
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="w-12 h-12 rounded-full bg-[#f8f9fa] flex items-center justify-center flex-shrink-0"><Mail className="w-5 h-5 text-[#666666]" strokeWidth={1.5} /></div>
|
||||
<div><h3 className="font-medium mb-1">Email</h3><p className="text-[#666666] text-sm">hello@manoonoils.com</p><p className="text-[#999999] text-xs mt-1">Nous répondons sous 24 heures</p></div>
|
||||
</div>
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="w-12 h-12 rounded-full bg-[#f8f9fa] flex items-center justify-center flex-shrink-0"><Truck className="w-5 h-5 text-[#666666]" strokeWidth={1.5} /></div>
|
||||
<div><h3 className="font-medium mb-1">Livraison</h3><p className="text-[#666666] text-sm">Livraison gratuite dès €50</p><p className="text-[#999999] text-xs mt-1">Livré sous 2-5 jours ouvrables</p></div>
|
||||
</div>
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="w-12 h-12 rounded-full bg-[#f8f9fa] flex items-center justify-center flex-shrink-0"><MapPin className="w-5 h-5 text-[#666666]" strokeWidth={1.5} /></div>
|
||||
<div><h3 className="font-medium mb-1">Localisation</h3><p className="text-[#666666] text-sm">Serbie</p><p className="text-[#999999] text-xs mt-1">Expédition dans le monde entier</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-[#f8f9fa] p-8 md:p-10">
|
||||
{submitted ? (
|
||||
<div className="text-center py-12">
|
||||
<div className="w-16 h-16 rounded-full bg-green-100 flex items-center justify-center mx-auto mb-4"><Check className="w-8 h-8 text-green-600" strokeWidth={1.5} /></div>
|
||||
<h3 className="text-xl font-medium mb-2">Merci!</h3>
|
||||
<p className="text-[#666666]">Votre message a été envoyé. Nous reviendrons vers vous bientôt.</p>
|
||||
</div>
|
||||
) : (
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
<div><label htmlFor="name" className="block text-sm font-medium mb-2">Nom</label><input type="text" id="name" required value={formData.name} onChange={(e) => setFormData({ ...formData, name: e.target.value })} className="w-full px-4 py-3 bg-white border border-[#e5e5e5] focus:outline-none focus:border-black transition-colors" placeholder="Votre nom" /></div>
|
||||
<div><label htmlFor="email" className="block text-sm font-medium mb-2">Email</label><input type="email" id="email" required value={formData.email} onChange={(e) => setFormData({ ...formData, email: e.target.value })} className="w-full px-4 py-3 bg-white border border-[#e5e5e5] focus:outline-none focus:border-black transition-colors" placeholder="votre@email.com" /></div>
|
||||
<div><label htmlFor="message" className="block text-sm font-medium mb-2">Message</label><textarea id="message" required rows={5} value={formData.message} onChange={(e) => setFormData({ ...formData, message: e.target.value })} className="w-full px-4 py-3 bg-white border border-[#e5e5e5] focus:outline-none focus:border-black transition-colors resize-none" placeholder="Comment pouvons-nous vous aider?" /></div>
|
||||
<button type="submit" className="w-full py-4 bg-black text-white text-sm uppercase tracking-[0.1em] font-medium hover:bg-[#333333] transition-colors">Envoyer Le Message</button>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="py-16 md:py-24 border-t border-[#e5e5e5]">
|
||||
<div className="container">
|
||||
<div className="max-w-3xl mx-auto">
|
||||
<h2 className="text-2xl font-medium text-center mb-12">Questions Fréquentes</h2>
|
||||
<div className="space-y-6">
|
||||
{[
|
||||
{ q: "Combien de temps dure la livraison?", a: "Les commandes sont généralement livrées sous 2-5 jours ouvrables pour la livraison nationale. Vous recevrez un numéro de suivi une fois votre commande expédiée." },
|
||||
{ q: "Vos produits sont-ils 100% naturels?", a: "Oui! Toutes nos huiles sont 100% naturelles, pressées à froid et sans additifs, conservateurs ou parfums artificiels." },
|
||||
{ q: "Quelle est votre politique de retour?", a: "Nous acceptons les retours dans les 14 jours suivant la livraison pour les produits non ouverts. Veuillez nous contacter si vous avez des problèmes avec votre commande." },
|
||||
{ q: "Offrez-vous la vente en gros?", a: "Oui, nous proposons des prix de gros pour les commandes en vrac. Veuillez nous contacter à hello@manoonoils.com pour plus d'informations." }
|
||||
].map((faq, index) => (<div key={index} className="border-b border-[#e5e5e5] pb-6"><h3 className="font-medium mb-2">{faq.q}</h3><p className="text-[#666666] text-sm leading-relaxed">{faq.a}</p></div>))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<div className="pt-16"><Footer /></div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
117
src/app/fr/page.tsx
Normal file
117
src/app/fr/page.tsx
Normal file
@@ -0,0 +1,117 @@
|
||||
import { getProducts } from "@/lib/saleor";
|
||||
import Header from "@/components/layout/Header";
|
||||
import Footer from "@/components/layout/Footer";
|
||||
import HeroVideo from "@/components/home/HeroVideo";
|
||||
import ProductCard from "@/components/product/ProductCard";
|
||||
import TrustBadges from "@/components/home/TrustBadges";
|
||||
import AsSeenIn from "@/components/home/AsSeenIn";
|
||||
import ProductReviews from "@/components/product/ProductReviews";
|
||||
import BeforeAfterGallery from "@/components/home/BeforeAfterGallery";
|
||||
import ProblemSection from "@/components/home/ProblemSection";
|
||||
import HowItWorks from "@/components/home/HowItWorks";
|
||||
|
||||
export const metadata = {
|
||||
title: "ManoonOils - Huiles Naturelles Premium pour Cheveux & Peau",
|
||||
description:
|
||||
"Découvrez notre collection premium d'huiles naturelles pour les soins capillaires et cutanés. Fait main avec amour en utilisant uniquement les meilleurs ingrédients.",
|
||||
};
|
||||
|
||||
export default async function FrenchHomepage() {
|
||||
let products: any[] = [];
|
||||
try {
|
||||
products = await getProducts("FR");
|
||||
} catch (e) {
|
||||
console.log("Failed to fetch products during build");
|
||||
}
|
||||
|
||||
const featuredProducts = products?.slice(0, 4) || [];
|
||||
const hasProducts = featuredProducts.length > 0;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-white">
|
||||
<HeroVideo />
|
||||
<AsSeenIn />
|
||||
<ProductReviews />
|
||||
<TrustBadges />
|
||||
<ProblemSection />
|
||||
<BeforeAfterGallery />
|
||||
<div id="main_content" className="scroll-mt-[72px] lg:scroll-mt-[72px]">
|
||||
{hasProducts && (
|
||||
<section className="py-24 px-4 sm:px-6 lg:px-8 bg-white">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="text-center mb-16">
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-3 block">Notre Collection</span>
|
||||
<h2 className="text-3xl md:text-4xl font-medium mb-4">Huiles Naturelles Premium</h2>
|
||||
<p className="text-[#666666] max-w-xl mx-auto">Pressées à froid, pures et naturelles pour votre routine beauté quotidienne</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 lg:gap-8">
|
||||
{featuredProducts.map((product, index) => (
|
||||
<ProductCard key={product.id} product={product} index={index} locale="FR" />
|
||||
))}
|
||||
</div>
|
||||
<div className="text-center mt-12">
|
||||
<a href="/fr/products" className="inline-block text-sm uppercase tracking-[0.1em] border-b border-black pb-1 hover:text-[#666666] hover:border-[#666666] transition-colors">Voir Tous Les Produits</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
<HowItWorks />
|
||||
<section className="py-24 px-4 sm:px-6 lg:px-8 bg-[#f8f9fa]">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 lg:gap-20 items-center">
|
||||
<div>
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-3 block">Notre Histoire</span>
|
||||
<h2 className="text-3xl md:text-4xl font-medium mb-6">Fait Main avec Amour</h2>
|
||||
<p className="text-[#666666] mb-6 leading-relaxed">Chaque flacon de ManoonOils est fabriqué avec soin en utilisant des méthodes traditionnelles transmises de génération en génération. Nous ne sélectionnons que les meilleurs ingrédients biologiques pour vous apporter des huiles qui nourrissent les cheveux et la peau.</p>
|
||||
<p className="text-[#666666] mb-8 leading-relaxed">Notre engagement envers la pureté signifie pas d'additifs, pas de préservatifs - juste la bonté de la nature sous sa forme la plus potente.</p>
|
||||
<a href="/fr/about" className="inline-block text-sm uppercase tracking-[0.1em] border-b border-black pb-1 hover:text-[#666666] hover:border-[#666666] transition-colors">En Savoir Plus</a>
|
||||
</div>
|
||||
<div className="relative aspect-[4/3] bg-[#e8f0f5] rounded-lg overflow-hidden">
|
||||
<img src="https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?q=80&w=800&auto=format&fit=crop" alt="Production d'huiles naturelles" className="w-full h-full object-cover" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="py-24 px-4 sm:px-6 lg:px-8 bg-gradient-to-b from-white to-[#faf9f7]">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="text-center mb-16">
|
||||
<span className="text-xs uppercase tracking-[0.3em] text-[#c9a962] mb-4 block font-medium">Pourquoi Nous Choisir</span>
|
||||
<h2 className="text-3xl md:text-4xl lg:text-5xl font-medium text-[#1a1a1a]">La Différence Manoon</h2>
|
||||
<div className="w-24 h-1 bg-gradient-to-r from-[#c9a962] to-[#FFD700] mx-auto mt-6 rounded-full" />
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 lg:gap-8">
|
||||
{[
|
||||
{ title: "100% Naturel", description: "Huiles pures pressées à froid sans additifs ni préservatifs. Juste la bonté de la nature.", icon: (<svg className="w-10 h-10" viewBox="0 0 24 24" fill="none"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" fill="#7eb89e"/><path stroke="#7eb89e" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>) },
|
||||
{ title: "Artisanal", description: "Chaque lot est soigneusement préparé à la main pour garantir la plus haute qualité.", icon: (<svg className="w-10 h-10" viewBox="0 0 24 24" fill="none"><path stroke="#c9a962" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" 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: "Durable", description: "Ingrédients sourcés de manière éthique et emballage écologique pour une meilleure planète.", icon: (<svg className="w-10 h-10" viewBox="0 0 24 24" fill="none"><path stroke="#e8967a" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" d="M12.75 3.03v.568c0 .334.148.65.405.864l1.068.89c.442.369.535 1.01.216 1.49l-.51.766a2.25 2.25 0 01-1.161.886l-.143.048a1.107 1.107 0 00-.57 1.664c.369.555.169 1.307-.427 1.605L9 13.125l.423 1.059a.956.956 0 11-1.652.928l-.714-.093a1.125 1.125 0 00-1.906.172L4.5 15.75l-.612.153M12.75 3.031l.002-.004m0 0a8.955 8.955 0 00-4.943.834 8.974 8.974 0 004.943.834m4.943-.834a8.955 8.955 0 00-4.943-.834c2.687 0 5.18.948 7.161 2.664a8.974 8.974 0 014.943-.834z"/></svg>) },
|
||||
].map((benefit, index) => (
|
||||
<div key={index} className="relative text-center p-8 bg-white rounded-3xl shadow-lg border border-[#f0ede8] hover:shadow-2xl hover:border-[#c9a962]/30 transition-all duration-500 group">
|
||||
<div className="w-20 h-20 mx-auto mb-6 rounded-2xl bg-gradient-to-br from-[#faf9f7] to-[#f5f0e8] flex items-center justify-center shadow-md border border-[#e8e4dc] group-hover:border-[#c9a962]/50 transition-colors duration-300">{benefit.icon}</div>
|
||||
<h3 className="text-xl font-semibold text-[#1a1a1a] mb-3">{benefit.title}</h3>
|
||||
<p className="text-sm text-[#666666] leading-relaxed">{benefit.description}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="py-28 lg:py-32 px-4 sm:px-6 lg:px-8 bg-[#1a1a1a] text-white">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="max-w-2xl mx-auto text-center">
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-white/60 mb-3 block">Restez Connecté</span>
|
||||
<h2 className="text-3xl md:text-4xl lg:text-5xl font-medium mb-6">Rejoignez Notre Communauté</h2>
|
||||
<p className="text-white/70 mb-10 mx-auto text-lg">Abonnez-vous pour recevoir des offres exclusives, des conseils beauté et être le premier à connaître les nouveaux produits.</p>
|
||||
<form className="flex flex-col sm:flex-row items-stretch justify-center max-w-md mx-auto gap-0">
|
||||
<input type="email" placeholder="Entrez votre email" className="flex-1 min-w-0 px-5 h-14 bg-white/10 border border-white/20 border-b-0 sm:border-b border-r-0 sm:border-r border-white/20 text-white placeholder:text-white/50 focus:border-white focus:outline-none transition-colors text-base text-center sm:text-left rounded-t sm:rounded-l sm:rounded-tr-none" />
|
||||
<button type="submit" className="px-8 h-14 bg-white text-black text-sm uppercase tracking-[0.1em] font-medium hover:bg-white/90 transition-colors whitespace-nowrap flex-shrink-0 rounded-b sm:rounded-r sm:rounded-bl-none">S'abonner</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
}
|
||||
83
src/app/fr/products/[slug]/page.tsx
Normal file
83
src/app/fr/products/[slug]/page.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import { getProductBySlug, getProducts, getLocalizedProduct } from "@/lib/saleor";
|
||||
import Header from "@/components/layout/Header";
|
||||
import Footer from "@/components/layout/Footer";
|
||||
import ProductDetail from "@/components/product/ProductDetail";
|
||||
import type { Product } from "@/types/saleor";
|
||||
|
||||
interface ProductPageProps {
|
||||
params: Promise<{ slug: string }>;
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
try {
|
||||
const products = await getProducts("FR", 100);
|
||||
const params: Array<{ slug: string }> = [];
|
||||
products.forEach((product: Product) => {
|
||||
if (product.translation?.slug) {
|
||||
params.push({ slug: product.translation.slug });
|
||||
}
|
||||
});
|
||||
return params;
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: ProductPageProps) {
|
||||
const { slug } = await params;
|
||||
const product = await getProductBySlug(slug, "FR");
|
||||
|
||||
if (!product) {
|
||||
return { title: "Produit Non Trouvé" };
|
||||
}
|
||||
|
||||
const localized = getLocalizedProduct(product, "FR");
|
||||
|
||||
return {
|
||||
title: localized.name,
|
||||
description: localized.seoDescription || localized.description?.slice(0, 160),
|
||||
openGraph: {
|
||||
title: localized.name,
|
||||
description: localized.seoDescription || localized.description?.slice(0, 160),
|
||||
images: product.media?.[0]?.url ? [product.media[0].url] : [],
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default async function FrenchProductPage({ params }: ProductPageProps) {
|
||||
const { slug } = await params;
|
||||
const product = await getProductBySlug(slug, "FR");
|
||||
|
||||
if (!product) {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-white">
|
||||
<div className="pt-[180px] lg:pt-[200px] pb-20 text-center px-4">
|
||||
<h1 className="text-2xl font-medium mb-4">Produit non trouvé</h1>
|
||||
<p className="text-[#666666] mb-8">Le produit que vous recherchez n'existe pas ou a été supprimé.</p>
|
||||
<a href="/fr/products" className="inline-block px-8 py-3 bg-black text-white text-sm uppercase tracking-[0.1em] hover:bg-[#333333] transition-colors">Parcourir Les Produits</a>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
let relatedProducts: Product[] = [];
|
||||
try {
|
||||
const allProducts = await getProducts("FR", 8);
|
||||
relatedProducts = allProducts.filter((p: Product) => p.id !== product.id).slice(0, 4);
|
||||
} catch (e) {}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-white">
|
||||
<ProductDetail product={product} relatedProducts={relatedProducts} locale="FR" />
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
}
|
||||
63
src/app/fr/products/page.tsx
Normal file
63
src/app/fr/products/page.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import { getProducts } from "@/lib/saleor";
|
||||
import Header from "@/components/layout/Header";
|
||||
import Footer from "@/components/layout/Footer";
|
||||
import ProductCard from "@/components/product/ProductCard";
|
||||
import { ChevronDown } from "lucide-react";
|
||||
|
||||
export const metadata = {
|
||||
title: "Produits - ManoonOils",
|
||||
description: "Parcourez notre collection d'huiles naturelles premium pour les soins capillaires et cutanés.",
|
||||
};
|
||||
|
||||
export default async function FrenchProductsPage() {
|
||||
const products = await getProducts("FR");
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-white">
|
||||
<div className="pt-[72px] lg:pt-[72px]">
|
||||
<div className="border-b border-[#e5e5e5]">
|
||||
<div className="container py-8 md:py-12">
|
||||
<div className="flex flex-col md:flex-row md:items-end md:justify-between gap-4">
|
||||
<div>
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-[#666666] mb-2 block">Notre Collection</span>
|
||||
<h1 className="text-3xl md:text-4xl font-medium">Tous Les Produits</h1>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-sm text-[#666666]">{products.length} produits</span>
|
||||
<div className="relative">
|
||||
<select className="appearance-none bg-transparent border border-[#e5e5e5] pl-4 pr-10 py-2 text-sm focus:outline-none focus:border-black cursor-pointer" defaultValue="featured">
|
||||
<option value="featured">En Vedette</option>
|
||||
<option value="newest">Nouveautés</option>
|
||||
<option value="price-low">Prix: Croissant</option>
|
||||
<option value="price-high">Prix: Décroissant</option>
|
||||
</select>
|
||||
<ChevronDown className="absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 pointer-events-none text-[#666666]" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<section className="py-12 md:py-16">
|
||||
<div className="container">
|
||||
{products.length === 0 ? (
|
||||
<div className="text-center py-20">
|
||||
<p className="text-[#666666] mb-4">Aucun produit disponible</p>
|
||||
<p className="text-sm text-[#999999]">Veuillez revenir plus tard pour les nouveaux arrivages.</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 lg:gap-8">
|
||||
{products.map((product, index) => (
|
||||
<ProductCard key={product.id} product={product} index={index} locale="FR" />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
<div className="pt-16"><Footer /></div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
import "./globals.css";
|
||||
import type { Metadata, Viewport } from "next";
|
||||
import ErrorBoundary from "@/components/providers/ErrorBoundary";
|
||||
import { NextIntlClientProvider } from "next-intl";
|
||||
import { getMessages } from "next-intl/server";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: {
|
||||
@@ -23,19 +25,25 @@ export const viewport: Viewport = {
|
||||
maximumScale: 5,
|
||||
};
|
||||
|
||||
// Suppress extension-caused hydration warnings
|
||||
const suppressHydrationWarning = true;
|
||||
|
||||
export default function RootLayout({
|
||||
export default async function RootLayout({
|
||||
children,
|
||||
params,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
params: Promise<{ locale: string }>;
|
||||
}) {
|
||||
const { locale } = await params;
|
||||
const messages = await getMessages();
|
||||
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<html lang={locale} suppressHydrationWarning>
|
||||
<body className="antialiased" suppressHydrationWarning>
|
||||
<ErrorBoundary>
|
||||
{children}
|
||||
<NextIntlClientProvider messages={messages}>
|
||||
{children}
|
||||
</NextIntlClientProvider>
|
||||
</ErrorBoundary>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { defineRouting } from 'next-intl/routing';
|
||||
import { defineRouting } from "next-intl/routing";
|
||||
|
||||
export const routing = defineRouting({
|
||||
locales: ['sr', 'en'],
|
||||
defaultLocale: 'sr',
|
||||
localePrefix: 'as-needed'
|
||||
locales: ["sr", "en", "de", "fr"],
|
||||
defaultLocale: "sr",
|
||||
localePrefix: "as-needed",
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user