first commit

This commit is contained in:
mstfyldz
2026-05-30 18:23:21 +03:00
commit e927cd6af3
57 changed files with 12945 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+196
View File
@@ -0,0 +1,196 @@
"use client";
import { motion, AnimatePresence } from "framer-motion";
import { useState } from "react";
import Link from "next/link";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import type { Locale } from "@/i18n-config";
import { blogPosts, BlogPost } from "@/data/blog";
const expo = [0.16, 1, 0.3, 1] as [number, number, number, number];
export default function BlogClient({
lang,
dict,
initialPosts,
}: {
lang: Locale;
dict: any;
initialPosts?: BlogPost[];
}) {
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
const [searchQuery, setSearchQuery] = useState("");
const postsList = initialPosts && initialPosts.length > 0 ? initialPosts : blogPosts;
const categories = Array.from(
new Set(
postsList.map((post) => {
const content = post[lang] || post.en;
return (content.category as string).split(" · ")[0]; // Main category e.g. YZ, Web3, Web
})
)
);
const filteredPosts = postsList.filter((post) => {
const content = post[lang] || post.en;
const matchesCategory =
!selectedCategory || (content.category as string).startsWith(selectedCategory);
const matchesSearch =
(content.title as string).toLowerCase().includes(searchQuery.toLowerCase()) ||
(content.excerpt as string).toLowerCase().includes(searchQuery.toLowerCase()) ||
(content.tags as string[]).some((t: string) => t.toLowerCase().includes(searchQuery.toLowerCase()));
return matchesCategory && matchesSearch;
});
return (
<div className="bg-[#F4F0E8] text-[#0A0A0A] font-body min-h-screen">
<Header lang={lang} dict={dict.nav} />
<main className="pt-32 pb-24 px-6 max-w-7xl mx-auto">
{/* Header Block */}
<div className="border-b border-[#C8C2B8] pb-12 mb-12">
<div className="flex items-center gap-3 mb-6">
<div className="w-3 h-3 bg-[#FFE600]" />
<span className="font-mono text-[10px] tracking-[0.3em] uppercase text-[#A0998E]">
{dict.blog.badge}
</span>
</div>
<motion.h1
className="font-display font-black text-5xl sm:text-6xl lg:text-8xl uppercase leading-[0.85] tracking-tight"
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, ease: expo }}
>
{dict.blog.title}
</motion.h1>
<p className="text-[#6A6460] mt-6 text-lg max-w-2xl font-light">
{dict.blog.desc}
</p>
</div>
{/* Filter Controls & Search */}
<div className="flex flex-col md:flex-row gap-6 justify-between items-stretch md:items-center mb-12">
{/* Categories */}
<div className="flex flex-wrap gap-2">
<button
onClick={() => setSelectedCategory(null)}
className={`font-mono text-[10px] tracking-[0.15em] uppercase px-4 py-2 border transition-all cursor-pointer ${
selectedCategory === null
? "bg-[#0A0A0A] text-[#F4F0E8] border-[#0A0A0A]"
: "border-[#C8C2B8] text-[#6A6460] hover:border-[#0A0A0A] hover:text-[#0A0A0A]"
}`}
>
{lang === "tr" ? "HEPSİ" : "ALL"}
</button>
{categories.map((cat) => (
<button
key={cat}
onClick={() => setSelectedCategory(cat)}
className={`font-mono text-[10px] tracking-[0.15em] uppercase px-4 py-2 border transition-all cursor-pointer ${
selectedCategory === cat
? "bg-[#0A0A0A] text-[#F4F0E8] border-[#0A0A0A]"
: "border-[#C8C2B8] text-[#6A6460] hover:border-[#0A0A0A] hover:text-[#0A0A0A]"
}`}
>
{cat}
</button>
))}
</div>
{/* Search Box */}
<div className="relative flex-grow md:max-w-xs">
<input
type="text"
placeholder={lang === "tr" ? "Arama yap..." : "Search..."}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] hover:border-[#0A0A0A] focus:border-[#0A0A0A] outline-none px-4 py-3 placeholder-[#A0998E] text-[#0A0A0A] transition-colors"
/>
{searchQuery && (
<button
onClick={() => setSearchQuery("")}
className="absolute right-3 top-1/2 -translate-y-1/2 text-[10px] font-mono text-[#A0998E] hover:text-[#0A0A0A] cursor-pointer"
>
[X]
</button>
)}
</div>
</div>
{/* Grid List */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<AnimatePresence mode="popLayout">
{filteredPosts.map((post, idx) => {
const content = post[lang] || post.en;
const accent = ["#FFE600", "#FF4500", "#00CC77"][idx % 3] || "#FFE600";
return (
<motion.div
key={post.slug}
layout
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
transition={{ duration: 0.4, ease: expo }}
className="group flex flex-col bg-[#F4F0E8] border border-[#C8C2B8] hover:border-[#0A0A0A] p-8 relative overflow-hidden transition-all duration-300 h-full"
whileHover={{ y: -6, backgroundColor: "#EDE8E0", boxShadow: "4px 4px 0px 0px #0A0A0A" }}
>
<div className="flex items-center gap-3 mb-6">
<span
className="font-mono text-[9px] tracking-[0.2em] uppercase px-2.5 py-1 border border-[#C8C2B8] text-[#6A6460]"
style={{ borderLeftColor: accent, borderLeftWidth: 3 }}
>
{content.category}
</span>
<span className="font-mono text-[9px] text-[#A0998E]">
{post.date}
</span>
</div>
<h3 className="font-display font-black text-xl uppercase text-[#0A0A0A] mb-4 leading-tight">
{content.title}
</h3>
<p className="text-[#6A6460] text-[13px] leading-relaxed mb-8 flex-grow">
{content.excerpt}
</p>
<div className="pt-6 border-t border-[#C8C2B8] flex items-center justify-between mt-auto">
<div className="flex flex-col">
<span className="font-display font-black text-[11px] uppercase text-[#0A0A0A]">{post.author}</span>
<span className="font-mono text-[9px] text-[#A0998E] uppercase tracking-wider">{post.authorRole}</span>
</div>
<Link
href={`/${lang}/blog/${post.slug}`}
className="w-10 h-10 border border-[#C8C2B8] group-hover:border-[#0A0A0A] group-hover:bg-[#0A0A0A] group-hover:text-[#FFE600] text-[#0A0A0A] flex items-center justify-center transition-all"
>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<line x1="5" y1="12" x2="19" y2="12" />
<polyline points="12 5 19 12 12 19" />
</svg>
</Link>
</div>
{/* Category Accent Stripe */}
<div className="absolute top-0 left-0 right-0 h-1 transition-colors" style={{ backgroundColor: accent }} />
</motion.div>
);
})}
</AnimatePresence>
{filteredPosts.length === 0 && (
<div className="col-span-full py-16 text-center border border-dashed border-[#C8C2B8]">
<p className="font-mono text-xs uppercase text-[#A0998E]">
{lang === "tr" ? "Sonuç bulunamadı." : "No entries match your parameters."}
</p>
</div>
)}
</div>
</main>
<Footer lang={lang} dict={dict} />
</div>
);
}
+192
View File
@@ -0,0 +1,192 @@
"use client";
import { motion, useScroll, useSpring } from "framer-motion";
import Link from "next/link";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import type { Locale } from "@/i18n-config";
import type { BlogPost } from "@/data/blog";
const expo = [0.16, 1, 0.3, 1] as [number, number, number, number];
export default function BlogDetailClient({
lang,
dict,
post,
}: {
lang: Locale;
dict: any;
post: BlogPost;
}) {
const { scrollYProgress } = useScroll();
const scaleX = useSpring(scrollYProgress, {
stiffness: 100,
damping: 30,
restDelta: 0.001,
});
const content = post[lang] || post.en;
const accent = "#FFE600"; // Signature yellow
return (
<div className="bg-[#F4F0E8] text-[#0A0A0A] font-body min-h-screen">
{/* Scroll indicator */}
<motion.div
className="fixed top-0 left-0 right-0 h-1.5 bg-[#FFE600] z-50 origin-[0%]"
style={{ scaleX }}
/>
<Header lang={lang} dict={dict.nav} />
<main className="pt-32 pb-24 px-6 max-w-4xl mx-auto">
{/* Back Link */}
<motion.div
className="mb-8"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
>
<Link
href={`/${lang}/blog`}
className="inline-flex items-center gap-2 font-mono text-[10px] tracking-[0.25em] uppercase text-[#A0998E] hover:text-[#0A0A0A] transition-colors"
>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<line x1="19" y1="12" x2="5" y2="12" />
<polyline points="12 19 5 12 12 5" />
</svg>
{dict.blog.back}
</Link>
</motion.div>
{/* Article Metadata */}
<div className="flex items-center gap-3 mb-6">
<span
className="font-mono text-[9px] tracking-[0.2em] uppercase px-2.5 py-1 border border-[#C8C2B8] text-[#6A6460]"
style={{ borderLeftColor: accent, borderLeftWidth: 3 }}
>
{content.category}
</span>
<span className="font-mono text-[9px] text-[#A0998E]">
{post.date}
</span>
<span className="text-[#C8C2B8]"></span>
<span className="font-mono text-[9px] text-[#A0998E] uppercase tracking-wider">
{content.readingTime}
</span>
</div>
{/* Title */}
<motion.h1
className="font-display font-black text-4xl sm:text-5xl lg:text-6xl uppercase leading-[0.95] tracking-tight mb-8"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, ease: expo }}
>
{content.title}
</motion.h1>
{/* Author Bio Row */}
<motion.div
className="flex items-center gap-4 py-6 border-y border-[#C8C2B8] mb-12"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.2 }}
>
<div className="w-10 h-10 border border-[#C8C2B8] bg-[#FFE600] flex items-center justify-center font-display font-black text-xs text-[#0A0A0A]">
{post.author.charAt(0)}{post.author.split(" ")[1]?.charAt(0)}
</div>
<div>
<div className="font-display font-black text-[12px] uppercase text-[#0A0A0A]">
{post.author}
</div>
<div className="font-mono text-[9px] text-[#A0998E] uppercase tracking-wider">
{post.authorRole}
</div>
</div>
</motion.div>
{/* Featured Image */}
{post.image && (
<motion.div
className="border border-[#C8C2B8] p-2 bg-[#EDE8E0] mb-12 relative overflow-hidden group"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3 }}
>
<img
src={post.image}
alt={content.title}
className="w-full h-auto object-cover grayscale contrast-125 group-hover:grayscale-0 transition-all duration-700"
/>
</motion.div>
)}
{/* Article Body Content */}
<motion.article
className="prose prose-stone max-w-none text-[#4A4440] leading-relaxed text-[15px] space-y-6"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.4 }}
>
{/* Render paragraph chunks dynamically */}
{content.content.split("\n\n").map((paragraph, index) => {
if (paragraph.startsWith("## ")) {
return (
<h2 key={index} className="font-display font-black text-2xl uppercase text-[#0A0A0A] pt-6 mb-2">
{paragraph.replace("## ", "")}
</h2>
);
}
if (paragraph.startsWith("### ")) {
return (
<h3 key={index} className="font-display font-black text-lg uppercase text-[#0A0A0A] pt-4 mb-2">
{paragraph.replace("### ", "")}
</h3>
);
}
if (paragraph.startsWith("> ")) {
return (
<blockquote key={index} className="border-l-4 border-[#FFE600] pl-6 font-display font-bold uppercase text-[13px] text-[#0A0A0A] italic my-6">
{paragraph.replace("> ", "")}
</blockquote>
);
}
if (paragraph.startsWith("- ")) {
return (
<ul key={index} className="list-disc pl-6 space-y-2 font-mono text-xs text-[#6A6460]">
{paragraph.split("\n").map((li, idx) => (
<li key={idx}>{li.replace("- ", "")}</li>
))}
</ul>
);
}
if (paragraph.includes("```")) {
const codeLines = paragraph.split("\n").filter(l => !l.includes("```"));
const codeHeader = codeLines[0]?.startsWith("//") ? codeLines.shift() : "";
return (
<div key={index} className="font-mono text-xs bg-[#EDE8E0] p-5 border border-[#C8C2B8] my-6 overflow-x-auto text-[#0A0A0A]">
{codeHeader && <div className="text-[#A0998E] pb-3 border-b border-[#C8C2B8] mb-3">{codeHeader}</div>}
<pre className="whitespace-pre-wrap leading-relaxed">{codeLines.join("\n")}</pre>
</div>
);
}
return <p key={index}>{paragraph}</p>;
})}
</motion.article>
{/* Tags Block */}
<div className="flex flex-wrap gap-2 pt-12 mt-12 border-t border-[#C8C2B8]">
{content.tags.map((tag) => (
<span
key={tag}
className="font-mono text-[9px] tracking-wider uppercase px-2.5 py-1.5 border border-[#C8C2B8] text-[#6A6460] hover:border-[#0A0A0A] hover:text-[#0A0A0A] transition-colors cursor-default"
>
#{tag}
</span>
))}
</div>
</main>
<Footer lang={lang} dict={dict} />
</div>
);
}
+141
View File
@@ -0,0 +1,141 @@
"use client";
import { motion } from "framer-motion";
import { useState } from "react";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import type { Locale } from "@/i18n-config";
const easeOutExpo = [0.16, 1, 0.3, 1] as [number, number, number, number];
const fadeUp = {
hidden: { opacity: 0, y: 30 },
show: { opacity: 1, y: 0, transition: { duration: 0.8, ease: easeOutExpo } },
};
const stagger = {
hidden: {},
show: { transition: { staggerChildren: 0.1 } },
};
export default function ContactClient({ lang, dict }: { lang: Locale; dict: any }) {
const [formState, setFormState] = useState({
name: "",
email: "",
company: "",
service: "AI Solutions",
message: "",
});
const [submitted, setSubmitted] = useState(false);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
setSubmitted(true);
};
return (
<div className="bg-[#F4F0E8] text-[#0A0A0A] font-body min-h-screen">
<Header lang={lang} dict={dict.nav} />
<main className="pt-32 pb-24 px-6 min-h-screen max-w-4xl mx-auto">
<div className="border-b border-[#C8C2B8] pb-12 mb-16">
<div className="flex items-center gap-3 mb-6">
<div className="w-3 h-3 bg-[#FFE600]" />
<span className="font-mono text-[10px] tracking-[0.3em] uppercase text-[#A0998E]">{dict.contact.badge}</span>
</div>
<h1 className="font-display font-black text-5xl sm:text-6xl lg:text-8xl uppercase leading-[0.85] tracking-tight">
{dict.contact.title}
</h1>
</div>
{/* Contact Grid */}
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12">
{/* Info Side */}
<div className="lg:col-span-5 space-y-0">
<div className="border-b border-[#C8C2B8] pb-8 mb-8">
<div className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] mb-3">{dict.contact.infoBase}</div>
<div className="font-display font-black text-base text-[#0A0A0A]">{dict.contact.infoBaseText}</div>
<div className="font-mono text-[11px] text-[#A0998E] mt-1">{dict.contact.infoBaseSub}</div>
</div>
<div className="border-b border-[#C8C2B8] pb-8 mb-8">
<div className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] mb-3">{dict.contact.infoDirect}</div>
<a href="mailto:hello@ayristech.com" className="font-display font-black text-base text-[#0A0A0A] hover:text-[#FF4500] transition-colors block">hello@ayristech.com</a>
<a href="tel:+905320000000" className="font-mono text-[12px] text-[#A0998E] hover:text-[#0A0A0A] transition-colors mt-1 block">+90 (532) 000 00 00</a>
</div>
<div className="pb-8">
<div className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] mb-3">{dict.contact.infoBlueprint}</div>
<p className="text-[#7A7470] text-[13px] leading-relaxed">{dict.contact.infoBlueprintText}</p>
</div>
<div className="bg-[#FFE600] border-2 border-[#0A0A0A] p-6">
<p className="font-display font-black text-sm uppercase text-[#0A0A0A]">
{lang === "tr" ? "12 saat içinde yanıt alırsınız." : "Response within 12 operational hours."}
</p>
</div>
</div>
{/* Form Side */}
<div className="lg:col-span-7">
{submitted ? (
<motion.div
className="border-2 border-[#0A0A0A] bg-[#FFE600] p-8 sm:p-12 text-center h-full flex flex-col justify-center items-center"
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.6 }}
>
<div className="w-12 h-12 border-2 border-[#0A0A0A] bg-[#0A0A0A] flex items-center justify-center mb-6">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#FFE600" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12" /></svg>
</div>
<h3 className="font-display font-black text-2xl uppercase tracking-tight mb-2">{dict.contact.submittedTitle}</h3>
<p className="text-[#3A3A3A] text-[13px] max-w-sm">{dict.contact.submittedText}</p>
</motion.div>
) : (
<form onSubmit={handleSubmit} className="space-y-6">
<div>
<label className="block font-mono text-[9px] font-bold uppercase tracking-[0.3em] text-[#A0998E] mb-2">{dict.contact.formName}</label>
<input type="text" required value={formState.name} onChange={e => setFormState({ ...formState, name: e.target.value })} placeholder={dict.contact.formNamePlaceholder}
className="w-full bg-transparent border-b border-[#C8C2B8] focus:border-[#0A0A0A] outline-none py-3 text-sm text-[#0A0A0A] placeholder-[#C8C2B8] transition-colors" />
</div>
<div>
<label className="block font-mono text-[9px] font-bold uppercase tracking-[0.3em] text-[#A0998E] mb-2">{dict.contact.formEmail}</label>
<input type="email" required value={formState.email} onChange={e => setFormState({ ...formState, email: e.target.value })} placeholder={dict.contact.formEmailPlaceholder}
className="w-full bg-transparent border-b border-[#C8C2B8] focus:border-[#0A0A0A] outline-none py-3 text-sm text-[#0A0A0A] placeholder-[#C8C2B8] transition-colors" />
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
<div>
<label className="block font-mono text-[9px] font-bold uppercase tracking-[0.3em] text-[#A0998E] mb-2">{dict.contact.formCompany}</label>
<input type="text" value={formState.company} onChange={e => setFormState({ ...formState, company: e.target.value })} placeholder={dict.contact.formCompanyPlaceholder}
className="w-full bg-transparent border-b border-[#C8C2B8] focus:border-[#0A0A0A] outline-none py-3 text-sm text-[#0A0A0A] placeholder-[#C8C2B8] transition-colors" />
</div>
<div>
<label className="block font-mono text-[9px] font-bold uppercase tracking-[0.3em] text-[#A0998E] mb-2">{dict.contact.formTrack}</label>
<select value={formState.service} onChange={e => setFormState({ ...formState, service: e.target.value })}
className="w-full bg-transparent border-b border-[#C8C2B8] focus:border-[#0A0A0A] outline-none py-3 text-sm text-[#0A0A0A] transition-colors cursor-pointer">
<option value="AI Solutions" className="bg-[#F4F0E8]">{dict.services.items.ai.title}</option>
<option value="Blockchain Dev" className="bg-[#F4F0E8]">{dict.services.items.blockchain.title}</option>
<option value="Mobile Apps" className="bg-[#F4F0E8]">{dict.services.items.mobile.title}</option>
<option value="Web Platforms" className="bg-[#F4F0E8]">{dict.services.items.web.title}</option>
</select>
</div>
</div>
<div>
<label className="block font-mono text-[9px] font-bold uppercase tracking-[0.3em] text-[#A0998E] mb-2">{dict.contact.formScope}</label>
<textarea rows={4} required value={formState.message} onChange={e => setFormState({ ...formState, message: e.target.value })} placeholder={dict.contact.formScopePlaceholder}
className="w-full bg-transparent border-b border-[#C8C2B8] focus:border-[#0A0A0A] outline-none py-3 text-sm text-[#0A0A0A] placeholder-[#C8C2B8] transition-colors resize-none" />
</div>
<motion.button type="submit" className="btn-brutal btn-brutal-yellow w-full py-5 font-display font-black text-[13px] tracking-widest uppercase cursor-pointer" whileTap={{ scale: 0.98 }}>
{dict.contact.formSubmit}
</motion.button>
</form>
)}
</div>
</div>
</main>
<Footer lang={lang} dict={dict} />
</div>
);
}
+101
View File
@@ -0,0 +1,101 @@
"use client";
import { motion, AnimatePresence } from "framer-motion";
import { useState } from "react";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import type { Locale } from "@/i18n-config";
const easeOutExpo = [0.16, 1, 0.3, 1] as [number, number, number, number];
const fadeUp = {
hidden: { opacity: 0, y: 30 },
show: { opacity: 1, y: 0, transition: { duration: 0.8, ease: easeOutExpo } },
};
const stagger = {
hidden: {},
show: { transition: { staggerChildren: 0.1 } },
};
const IconPlus = () => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" className="w-4 h-4">
<line x1="12" y1="5" x2="12" y2="19" />
<line x1="5" y1="12" x2="19" y2="12" />
</svg>
);
export default function FAQClient({ lang, dict }: { lang: Locale; dict: any }) {
const [activeFaq, setActiveFaq] = useState<number | null>(null);
const faqs = dict.faq.items;
return (
<div className="bg-[#F4F0E8] text-[#0A0A0A] font-body min-h-screen">
<Header lang={lang} dict={dict.nav} />
<main className="pt-32 pb-24 px-6 min-h-screen max-w-3xl mx-auto">
{/* Header */}
<div className="border-b border-[#C8C2B8] pb-12 mb-16">
<div className="flex items-center gap-3 mb-6">
<div className="w-3 h-3 bg-[#FFE600]" />
<span className="font-mono text-[10px] tracking-[0.3em] uppercase text-[#A0998E]">{dict.faq.badge}</span>
</div>
<motion.h1
className="font-display font-black text-5xl sm:text-6xl lg:text-8xl uppercase leading-[0.85] tracking-tight"
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8 }}
>
{dict.faq.title}
</motion.h1>
</div>
{/* Accordions */}
<div>
{faqs.map((faq: any, idx: number) => (
<motion.div
key={idx}
className="border-b border-[#C8C2B8]"
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: idx * 0.06 }}
>
<button
className="w-full flex items-center justify-between py-6 text-left cursor-pointer group"
onClick={() => setActiveFaq(activeFaq === idx ? null : idx)}
>
<span className="font-display font-black text-base sm:text-lg uppercase text-[#0A0A0A] pr-8 leading-snug">{faq.q}</span>
<motion.div
className="flex-shrink-0 w-8 h-8 border border-[#C8C2B8] group-hover:border-[#0A0A0A] group-hover:bg-[#FFE600] text-[#8A8480] group-hover:text-[#0A0A0A] flex items-center justify-center transition-colors"
animate={{ rotate: activeFaq === idx ? 45 : 0 }}
>
<IconPlus />
</motion.div>
</button>
<AnimatePresence initial={false}>
{activeFaq === idx && (
<motion.div
initial={{ height: 0, opacity: 0 }}
animate={{ height: "auto", opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
transition={{ duration: 0.3, ease: easeOutExpo }}
>
<p className="text-[#6A6460] text-[14px] leading-relaxed pb-6 border-l-2 border-[#FFE600] pl-6">
{faq.a}
</p>
</motion.div>
)}
</AnimatePresence>
</motion.div>
))}
</div>
</main>
<Footer lang={lang} dict={dict} />
</div>
);
}
+117
View File
@@ -0,0 +1,117 @@
"use client";
import Link from "next/link";
import type { Locale } from "@/i18n-config";
export default function Footer({ lang, dict }: { lang: Locale; dict: any }) {
const spectrum = [
dict.services.items.ai.title,
dict.services.items.blockchain.title,
dict.services.items.mobile.title,
dict.services.items.web.title,
];
const registry = [
{ name: dict.nav.services, href: `/${lang}/services` },
{ name: dict.nav.work, href: `/${lang}/work` },
{ name: dict.nav.process, href: `/${lang}/process` },
{ name: dict.nav.blog, href: `/${lang}/blog` },
{ name: dict.nav.partners, href: `/${lang}/partners` },
{ name: dict.nav.faq, href: `/${lang}/faq` },
];
return (
<footer className="bg-[#EDE8E0] border-t border-[#C8C2B8]">
{/* Big CTA */}
<div className="border-b border-[#C8C2B8] px-6 py-20">
<div className="max-w-7xl mx-auto flex flex-col md:flex-row items-center justify-between gap-8">
<h2 className="font-display font-black text-4xl sm:text-5xl lg:text-6xl uppercase text-[#0A0A0A] leading-[0.9]">
Ready to build<br />
<span className="text-stroke">the impossible?</span>
</h2>
<Link
href={`/${lang}/contact`}
className="btn-brutal btn-brutal-yellow flex items-center gap-3 px-10 py-5 font-display font-black text-[13px] tracking-widest uppercase cursor-pointer flex-shrink-0"
>
{dict.nav.quote}
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<line x1="5" y1="12" x2="19" y2="12" />
<polyline points="12 5 19 12 12 19" />
</svg>
</Link>
</div>
</div>
{/* Links */}
<div className="px-6 py-16 border-b border-[#C8C2B8]">
<div className="max-w-7xl mx-auto grid grid-cols-2 md:grid-cols-4 gap-12">
{/* Brand */}
<div className="col-span-2">
<div className="flex items-center gap-3 mb-6">
<div className="w-8 h-8 bg-[#FFE600] border-2 border-[#0A0A0A] flex items-center justify-center font-display font-black text-[13px] text-[#0A0A0A]">
A
</div>
<span className="font-display font-black tracking-tight text-[15px] text-[#0A0A0A] uppercase">
{dict.nav.brandName}<span className="text-[#A0998E] font-medium">{dict.nav.brandSub}</span>
</span>
</div>
<p className="text-[#8A8480] text-[13px] leading-relaxed max-w-xs">
{dict.footer.desc}
</p>
</div>
{/* Spectrum */}
<div>
<div className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] mb-5">
{dict.footer.spectrum}
</div>
{spectrum.map(s => (
<Link
key={s}
href={`/${lang}/services`}
className="block text-[#6A6460] text-[13px] mb-3 hover:text-[#0A0A0A] transition-colors uppercase font-display font-bold tracking-tight"
>
{s}
</Link>
))}
</div>
{/* Registry */}
<div>
<div className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] mb-5">
{dict.footer.registry}
</div>
{registry.map(s => (
<Link
key={s.name}
href={s.href}
className="block text-[#6A6460] text-[13px] mb-3 hover:text-[#0A0A0A] transition-colors uppercase font-display font-bold tracking-tight"
>
{s.name}
</Link>
))}
</div>
</div>
</div>
{/* Bottom bar */}
<div className="px-6 py-6">
<div className="max-w-7xl mx-auto flex flex-col sm:flex-row justify-between items-center gap-4">
<p className="font-mono text-[10px] tracking-[0.2em] uppercase text-[#C8C2B8]">
© 2026 Ayris Tech {dict.footer.rights}
</p>
<div className="flex items-center gap-6">
<Link href="#" className="font-mono text-[10px] tracking-[0.15em] uppercase text-[#C8C2B8] hover:text-[#0A0A0A] transition-colors">
{dict.footer.privacy}
</Link>
<Link href="#" className="font-mono text-[10px] tracking-[0.15em] uppercase text-[#C8C2B8] hover:text-[#0A0A0A] transition-colors">
{dict.footer.terms}
</Link>
</div>
</div>
</div>
</footer>
);
}
+163
View File
@@ -0,0 +1,163 @@
"use client";
import { motion, AnimatePresence, useScroll } from "framer-motion";
import { useState, useEffect } from "react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import type { Locale } from "@/i18n-config";
const expo = [0.16, 1, 0.3, 1] as [number, number, number, number];
export default function Header({ lang, dict }: { lang: Locale; dict: any }) {
const [menuOpen, setMenuOpen] = useState(false);
const [scrolled, setScrolled] = useState(false);
const pathname = usePathname();
const { scrollY } = useScroll();
useEffect(() => {
const unsub = scrollY.on("change", (v) => setScrolled(v > 40));
return () => unsub();
}, [scrollY]);
const links = [
{ name: dict.services, href: `/${lang}/services` },
{ name: dict.work, href: `/${lang}/work` },
{ name: dict.process, href: `/${lang}/process` },
{ name: dict.blog, href: `/${lang}/blog` },
{ name: dict.partners, href: `/${lang}/partners` },
{ name: dict.faq, href: `/${lang}/faq` },
];
const otherLang = lang === "tr" ? "en" : "tr";
return (
<>
<motion.header
className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${
scrolled
? "bg-[#F4F0E8]/90 backdrop-blur-md border-b border-[#C8C2B8]"
: "bg-transparent"
}`}
initial={{ y: -80, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ duration: 0.8, ease: expo }}
>
<div className="max-w-7xl mx-auto px-6 h-16 flex items-center justify-between">
{/* Logo */}
<Link href={`/${lang}`} className="flex items-center gap-3 cursor-pointer group">
<div className="w-8 h-8 bg-[#FFE600] border-2 border-[#0A0A0A] flex items-center justify-center font-display font-black text-[13px] text-[#0A0A0A] group-hover:bg-[#FF4500] transition-colors duration-200">
A
</div>
<span className="font-display font-black tracking-tight text-[15px] text-[#0A0A0A] uppercase">
{dict.brandName}<span className="text-[#A0998E] font-medium">{dict.brandSub}</span>
</span>
</Link>
{/* Desktop nav */}
<nav className="hidden md:flex items-center gap-8">
{links.map(item => {
const isActive = pathname === item.href;
return (
<Link
key={item.name}
href={item.href}
className={`font-mono text-[10px] tracking-[0.2em] uppercase transition-colors duration-200 ${
isActive ? "text-[#0A0A0A] font-bold" : "text-[#A0998E] hover:text-[#0A0A0A]"
}`}
>
{item.name}
</Link>
);
})}
</nav>
{/* Right: lang + CTA */}
<div className="hidden md:flex items-center gap-4">
<Link
href={pathname.replace(`/${lang}`, `/${otherLang}`)}
className="font-mono text-[10px] tracking-[0.2em] uppercase text-[#A0998E] hover:text-[#0A0A0A] transition-colors duration-200 border border-[#C8C2B8] hover:border-[#0A0A0A] px-3 py-2"
>
{otherLang.toUpperCase()}
</Link>
<Link
href={`/${lang}/contact`}
className="btn-brutal btn-brutal-yellow flex items-center gap-2 px-5 py-2.5 font-display font-black text-[11px] tracking-widest uppercase cursor-pointer"
>
{dict.quote}
</Link>
</div>
{/* Mobile hamburger */}
<button
className="md:hidden flex flex-col justify-center items-center gap-1.5 w-10 h-10 cursor-pointer border border-[#C8C2B8] hover:border-[#0A0A0A] transition-colors"
onClick={() => setMenuOpen(!menuOpen)}
aria-label="Toggle Menu"
>
<motion.span
className="h-[1.5px] w-5 bg-[#0A0A0A] block"
animate={{ rotate: menuOpen ? 45 : 0, y: menuOpen ? 4.5 : 0 }}
transition={{ duration: 0.2 }}
/>
<motion.span
className="h-[1.5px] w-5 bg-[#0A0A0A] block"
animate={{ opacity: menuOpen ? 0 : 1, scaleX: menuOpen ? 0 : 1 }}
transition={{ duration: 0.2 }}
/>
<motion.span
className="h-[1.5px] w-5 bg-[#0A0A0A] block"
animate={{ rotate: menuOpen ? -45 : 0, y: menuOpen ? -4.5 : 0 }}
transition={{ duration: 0.2 }}
/>
</button>
</div>
</motion.header>
{/* Mobile menu overlay */}
<AnimatePresence>
{menuOpen && (
<motion.div
className="fixed inset-0 z-40 bg-[#F4F0E8] flex flex-col"
initial={{ clipPath: "inset(0 0 100% 0)" }}
animate={{ clipPath: "inset(0 0 0% 0)" }}
exit={{ clipPath: "inset(0 0 100% 0)" }}
transition={{ duration: 0.5, ease: expo }}
>
<div className="max-w-7xl mx-auto px-6 pt-20 pb-12 flex flex-col h-full">
<nav className="flex flex-col gap-1 flex-1 justify-center">
{links.map((item, idx) => (
<motion.div
key={item.name}
initial={{ x: -30, opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
exit={{ x: -30, opacity: 0 }}
transition={{ delay: idx * 0.07, duration: 0.4 }}
>
<Link
href={item.href}
className="block font-display font-black text-5xl uppercase text-[#C8C2B8] hover:text-[#0A0A0A] transition-colors duration-200 py-2"
onClick={() => setMenuOpen(false)}
>
{item.name}
</Link>
</motion.div>
))}
</nav>
<div className="border-t border-[#C8C2B8] pt-8">
<Link
href={`/${lang}/contact`}
className="btn-brutal btn-brutal-yellow inline-flex items-center gap-3 px-8 py-4 font-display font-black text-[13px] tracking-widest uppercase cursor-pointer"
onClick={() => setMenuOpen(false)}
>
{dict.quote}
</Link>
</div>
</div>
</motion.div>
)}
</AnimatePresence>
</>
);
}
+863
View File
@@ -0,0 +1,863 @@
"use client";
import {
motion,
AnimatePresence,
useScroll,
useTransform,
useMotionValue,
useSpring,
} from "framer-motion";
import { useRef, useState, useEffect, useCallback } from "react";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import type { Locale } from "@/i18n-config";
import Link from "next/link";
import { blogPosts } from "@/data/blog";
// ── EASING ──
const expo: [number, number, number, number] = [0.16, 1, 0.3, 1];
// ── SVG ICONS ──
const IconAI = () => (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<rect x="3" y="3" width="18" height="18" rx="1" />
<path d="M9 3v18M15 3v18M3 9h18M3 15h18" />
<circle cx="9" cy="9" r="1.5" fill="currentColor" />
<circle cx="15" cy="15" r="1.5" fill="currentColor" />
</svg>
);
const IconChain = () => (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" />
<path d="M3.27 6.96L12 12.01l8.73-5.05M12 22.08V12" />
</svg>
);
const IconMobile = () => (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<rect x="5" y="2" width="14" height="20" rx="2" />
<path d="M12 18h.01" />
</svg>
);
const IconWeb = () => (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<rect x="3" y="4" width="18" height="16" rx="1" />
<path d="M3 9h18M8 6h.01M11 6h.01M14 6h.01" />
</svg>
);
const IconArrow = () => (
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<line x1="5" y1="12" x2="19" y2="12" />
<polyline points="12 5 19 12 12 19" />
</svg>
);
const IconArrowUpRight = () => (
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<line x1="7" y1="17" x2="17" y2="7" />
<polyline points="7 7 17 7 17 17" />
</svg>
);
const IconPlus = () => (
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
<line x1="12" y1="5" x2="12" y2="19" />
<line x1="5" y1="12" x2="19" y2="12" />
</svg>
);
const IconCheck = () => (
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#0A0A0A" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<polyline points="20 6 9 17 4 12" />
</svg>
);
// ── ANIMATED COUNTER ──
function Counter({ target, suffix = "" }: { target: number; suffix?: string }) {
const [count, setCount] = useState(0);
const ref = useRef<HTMLSpanElement>(null);
const [started, setStarted] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => { if (entry.isIntersecting) setStarted(true); },
{ threshold: 0.5 }
);
if (ref.current) observer.observe(ref.current);
return () => observer.disconnect();
}, []);
useEffect(() => {
if (!started) return;
let cur = 0;
const steps = 50;
const inc = target / steps;
const iv = setInterval(() => {
cur += inc;
if (cur >= target) { setCount(target); clearInterval(iv); }
else setCount(Math.floor(cur));
}, 1600 / steps);
return () => clearInterval(iv);
}, [started, target]);
return <span ref={ref}>{count.toLocaleString()}{suffix}</span>;
}
// ── MAGNETIC BUTTON ──
function MagneticBtn({ children, className, href }: { children: React.ReactNode; className?: string; href?: string }) {
const ref = useRef<HTMLDivElement>(null);
const x = useMotionValue(0);
const y = useMotionValue(0);
const sx = useSpring(x, { stiffness: 200, damping: 20 });
const sy = useSpring(y, { stiffness: 200, damping: 20 });
const handleMouse = useCallback((e: React.MouseEvent) => {
if (!ref.current) return;
const { left, top, width, height } = ref.current.getBoundingClientRect();
x.set((e.clientX - left - width / 2) * 0.3);
y.set((e.clientY - top - height / 2) * 0.3);
}, [x, y]);
const handleLeave = useCallback(() => { x.set(0); y.set(0); }, [x, y]);
const Tag = href ? "a" : "div";
return (
<motion.div ref={ref} style={{ x: sx, y: sy }} onMouseMove={handleMouse} onMouseLeave={handleLeave} className="inline-block">
<Tag href={href} className={className}>{children}</Tag>
</motion.div>
);
}
// ── MARQUEE TEXT ──
function Marquee({ text, reverse = false }: { text: string; reverse?: boolean }) {
const repeated = Array(8).fill(text).join(" · ");
return (
<div className="marquee-wrapper border-y border-[#C8C2B8] bg-[#EDE8E0] py-3 overflow-hidden">
<div className={reverse ? "marquee-track-reverse" : "marquee-track"}>
{[0, 1].map(i => (
<span key={i} className="font-mono text-[11px] tracking-[0.35em] uppercase text-[#A0998E] px-8 whitespace-nowrap flex-shrink-0">
{repeated}
</span>
))}
</div>
</div>
);
}
// ── SPLIT TEXT ANIMATION ──
function SplitReveal({ text, className, delay = 0 }: { text: string; className?: string; delay?: number }) {
const words = text.split(" ");
return (
<span className={`inline-flex flex-wrap gap-x-[0.25em] ${className}`}>
{words.map((word, i) => (
<span key={i} className="overflow-hidden inline-block">
<motion.span
className="inline-block"
initial={{ y: "110%", rotate: 2 }}
whileInView={{ y: 0, rotate: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.75, ease: expo, delay: delay + i * 0.06 }}
>
{word}
</motion.span>
</span>
))}
</span>
);
}
// ── SECTION LABEL ──
function Label({ children }: { children: React.ReactNode }) {
return (
<div className="flex items-center gap-3 mb-6">
<div className="w-4 h-4 bg-[#FFE600] flex-shrink-0" />
<span className="font-mono text-[10px] tracking-[0.3em] uppercase text-[#A0998E]">{children}</span>
<div className="flex-1 h-px bg-[#C8C2B8]" />
</div>
);
}
// ── MAIN COMPONENT ──
export default function HomeClient({ lang, dict }: { lang: Locale; dict: any }) {
const heroRef = useRef<HTMLDivElement>(null);
const { scrollYProgress } = useScroll({ target: heroRef, offset: ["start start", "end start"] });
const heroY = useTransform(scrollYProgress, [0, 1], ["0%", "25%"]);
const heroOpacity = useTransform(scrollYProgress, [0, 0.7], [1, 0]);
const [activeFaq, setActiveFaq] = useState<number | null>(null);
const [formSent, setFormSent] = useState(false);
const [hoverCase, setHoverCase] = useState<number | null>(null);
const serviceIcons = [<IconAI />, <IconChain />, <IconMobile />, <IconWeb />];
const serviceCodes = ["AI / ML", "BC / WEB3", "MOB / DART", "WEB / NEXT"];
const services = dict.services.items
? Object.entries(dict.services.items as Record<string, { title: string; desc: string }>).map(([, val], idx) => ({
icon: serviceIcons[idx],
code: serviceCodes[idx],
title: val.title,
desc: val.desc,
items: [
["Predictive Models", "NLP Pipelines", "Computer Vision", "Agentic Workflows"],
["Smart Contract Audit", "DeFi Architecture", "Tokenomics Design", "Cross-chain Bridges"],
["Universal Codebase", "Offline Syncing", "Biometric Protocols", "Core Bundle Optimization"],
["Next.js App Router", "Server Components", "Headless Commerce", "Modular API Mesh"],
][idx],
}))
: [];
const caseStudies = (dict.work.items as any[]).map((item: any, idx: number) => ({
...item,
tech: [
["Python", "TensorFlow", "Next.js", "PostgreSQL"],
["Solidity", "React", "IPFS", "Node.js"],
["Flutter", "Firebase", "Django", "AWS"],
["Next.js", "Stripe", "Redis", "Vercel"],
][idx] || ["React", "TypeScript", "Node.js"],
accent: ["#FFE600", "#FF4500", "#0A0A0A", "#00CC77"][idx] || "#FFE600",
}));
const processes = dict.process.items as any[];
const featuredPosts = blogPosts;
const faqs = dict.faq.items as any[];
return (
<div className="bg-[#F4F0E8] text-[#0A0A0A] font-body selection:bg-[#FFE600] selection:text-[#0A0A0A]">
{/* Noise overlay */}
<div className="noise-overlay" />
<Header lang={lang} dict={dict.nav} />
{/* ──────────────── HERO ──────────────── */}
<section ref={heroRef} className="relative min-h-screen flex flex-col justify-end overflow-hidden border-b border-[#C8C2B8]">
{/* Dot grid bg */}
<motion.div
className="absolute inset-0 dot-grid opacity-60"
style={{ y: heroY, opacity: heroOpacity }}
/>
{/* Big watermark letters */}
<motion.div
className="absolute right-0 bottom-0 font-display font-black text-[22vw] leading-none text-[#E8E3DC] select-none pointer-events-none overflow-hidden"
style={{ y: useTransform(scrollYProgress, [0, 1], ["0%", "20%"]) }}
initial={{ opacity: 0, x: 40 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 1.2, delay: 0.5 }}
>
AT
</motion.div>
{/* Yellow right accent */}
<div className="absolute top-0 right-0 w-1 h-full bg-[#FFE600]" />
<div className="relative z-10 max-w-7xl mx-auto px-6 w-full pb-20 pt-40">
{/* Meta bar */}
<motion.div
className="flex items-center justify-between border-b border-[#C8C2B8] pb-6 mb-16"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.1, duration: 0.8 }}
>
<div className="flex items-center gap-3">
<span className="w-2 h-2 bg-[#00CC77] rounded-full animate-pulse" />
<span className="font-mono text-[10px] tracking-[0.25em] uppercase text-[#A0998E]">
{dict.hero.badge}
</span>
</div>
<span className="font-mono text-[10px] tracking-[0.2em] text-[#A0998E]">
EST. 2025 MUĞLA
</span>
</motion.div>
{/* Headline */}
<div className="mb-12">
<h1 className="font-display font-black uppercase leading-[0.85] tracking-tight">
<motion.div className="overflow-hidden" initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ delay: 0.15 }}>
<motion.span
className="block text-[15vw] sm:text-[12vw] lg:text-[10vw] text-[#0A0A0A]"
initial={{ y: "105%" }}
animate={{ y: 0 }}
transition={{ delay: 0.2, duration: 0.9, ease: expo }}
>
{dict.hero.titleLine1}
</motion.span>
</motion.div>
<motion.div className="overflow-hidden" initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ delay: 0.3 }}>
<motion.span
className="block text-[15vw] sm:text-[12vw] lg:text-[10vw] text-stroke"
initial={{ y: "105%" }}
animate={{ y: 0 }}
transition={{ delay: 0.35, duration: 0.9, ease: expo }}
>
{dict.hero.titleLine2}
</motion.span>
</motion.div>
</h1>
</div>
{/* Bottom bar */}
<motion.div
className="grid grid-cols-1 lg:grid-cols-12 gap-8 border-t border-[#C8C2B8] pt-10"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.6, duration: 0.8 }}
>
<div className="lg:col-span-5">
<p className="text-[#6A6460] text-base leading-relaxed max-w-md">
{dict.hero.desc}
</p>
</div>
<div className="lg:col-span-7 flex items-end justify-end gap-4 flex-wrap">
<MagneticBtn href={`/${lang}/contact`} className="btn-brutal btn-brutal-yellow inline-flex items-center gap-3 px-8 py-4 font-display font-black text-[13px] tracking-widest uppercase cursor-pointer">
{dict.hero.ctaQuote} <IconArrow />
</MagneticBtn>
<MagneticBtn href={`/${lang}/work`} className="btn-brutal inline-flex items-center gap-3 px-8 py-4 font-display font-black text-[13px] tracking-widest uppercase cursor-pointer">
{dict.hero.ctaWork}
</MagneticBtn>
</div>
</motion.div>
</div>
</section>
{/* ──────────────── MARQUEE 1 ──────────────── */}
<Marquee text="AI SOLUTIONS · BLOCKCHAIN DEV · MOBILE APPS · WEB PLATFORMS · DIGITAL TRANSFORMATION" />
{/* ──────────────── STATS ──────────────── */}
<section className="border-b border-[#C8C2B8] bg-[#F4F0E8]">
<div className="max-w-7xl mx-auto px-6 grid grid-cols-2 md:grid-cols-4">
{[
{ val: 48, suffix: "+", label: dict.stats.deliveries },
{ val: 98, suffix: "%", label: dict.stats.retention },
{ val: 12, suffix: "+", label: dict.stats.regions },
{ val: 1, suffix: "wk", label: lang === "tr" ? "MVP Süresi" : "Avg Cycle To MVP" },
].map((s, idx) => (
<motion.div
key={idx}
className={`py-12 px-6 flex flex-col justify-center ${idx < 3 ? "border-r border-[#C8C2B8]" : ""} ${idx < 2 ? "border-b md:border-b-0 border-[#C8C2B8]" : ""}`}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: idx * 0.1, duration: 0.6 }}
>
<div className="font-display font-black text-5xl sm:text-6xl text-[#0A0A0A] leading-none mb-2">
<Counter target={s.val} suffix={s.suffix} />
</div>
<div className="font-mono text-[10px] tracking-[0.25em] uppercase text-[#A0998E]">
{s.label}
</div>
</motion.div>
))}
</div>
</section>
{/* ──────────────── SERVICES ──────────────── */}
<section id="services" className="py-24 border-b border-[#C8C2B8]">
<div className="max-w-7xl mx-auto px-6">
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12 mb-16">
<div className="lg:col-span-7">
<Label>{dict.services.badge}</Label>
<h2 className="font-display font-black uppercase text-5xl sm:text-6xl lg:text-7xl leading-[0.9] tracking-tight">
<SplitReveal text={dict.services.title} />
</h2>
</div>
<div className="lg:col-span-5 flex items-end">
<p className="text-[#6A6460] leading-relaxed border-l-2 border-[#FFE600] pl-6">
{dict.services.desc}
</p>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-px bg-[#C8C2B8]">
{services.map((s, idx) => (
<motion.div
key={idx}
className="group bg-[#F4F0E8] p-10 cursor-pointer relative overflow-hidden"
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: idx * 0.1 }}
whileHover={{ backgroundColor: "#EDE8E0" }}
>
{/* Hover accent left bar */}
<motion.div
className="absolute left-0 top-0 bottom-0 w-1 bg-[#FFE600]"
initial={{ scaleY: 0 }}
whileHover={{ scaleY: 1 }}
transition={{ duration: 0.2 }}
style={{ transformOrigin: "top" }}
/>
<div className="flex items-start justify-between mb-8">
<div className="w-12 h-12 border border-[#C8C2B8] group-hover:border-[#0A0A0A] group-hover:bg-[#0A0A0A] group-hover:text-[#FFE600] flex items-center justify-center text-[#6A6460] transition-colors duration-200">
{s.icon}
</div>
<span className="font-mono text-[10px] tracking-[0.2em] uppercase text-[#C8C2B8] group-hover:text-[#A0998E] transition-colors duration-200">
{s.code}
</span>
</div>
<h3 className="font-display font-black text-2xl uppercase text-[#0A0A0A] mb-3 group-hover:text-[#0A0A0A] transition-colors duration-200">
{s.title}
</h3>
<p className="text-[#8A8480] text-sm leading-relaxed mb-8">
{s.desc}
</p>
<div className="flex flex-wrap gap-2 pt-6 border-t border-[#D8D3CA]">
{s.items?.map((item: string) => (
<span key={item} className="font-mono text-[10px] tracking-wider uppercase px-3 py-1.5 border border-[#C8C2B8] text-[#8A8480] group-hover:border-[#0A0A0A] group-hover:text-[#0A0A0A] transition-colors">
{item}
</span>
))}
</div>
{/* Number watermark */}
<div className="absolute bottom-4 right-6 font-display font-black text-[6rem] leading-none text-[#E8E3DC] select-none pointer-events-none">
{String(idx + 1).padStart(2, "0")}
</div>
</motion.div>
))}
</div>
</div>
</section>
{/* ──────────────── MARQUEE 2 ──────────────── */}
<Marquee text="CASE STUDIES · FINTECH · WEB3 · HEALTHCARE · E-COMMERCE · ENTERPRISE SCALE" reverse />
{/* ──────────────── CASE STUDIES ──────────────── */}
<section id="work" className="py-24 border-b border-[#C8C2B8]">
<div className="max-w-7xl mx-auto px-6">
<div className="mb-16">
<Label>{dict.work.badge}</Label>
<h2 className="font-display font-black uppercase text-5xl sm:text-6xl lg:text-7xl leading-[0.9] tracking-tight">
<SplitReveal text={dict.work.title} />
</h2>
</div>
<div className="border-t border-[#C8C2B8]">
{caseStudies.map((study: any, idx: number) => (
<motion.div
key={idx}
className="group border-b border-[#C8C2B8] cursor-pointer"
onHoverStart={() => setHoverCase(idx)}
onHoverEnd={() => setHoverCase(null)}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: idx * 0.08 }}
>
<div className="grid grid-cols-12 items-center py-8 gap-6">
{/* Index */}
<div className="col-span-1 hidden md:block">
<span className="font-mono text-[10px] text-[#C8C2B8]">{study.num}</span>
</div>
{/* Title */}
<div className="col-span-12 md:col-span-4">
<div className="flex items-center gap-4">
<motion.div
className="w-10 h-10 flex-shrink-0 flex items-center justify-center font-display font-black text-[11px] border-2 border-[#0A0A0A]"
style={{ backgroundColor: hoverCase === idx ? study.accent : "transparent", color: "#0A0A0A" }}
animate={{ rotate: hoverCase === idx ? 45 : 0 }}
transition={{ duration: 0.2 }}
>
</motion.div>
<h3 className="font-display font-black text-xl uppercase text-[#0A0A0A] group-hover:text-[#0A0A0A]">
{study.title}
</h3>
</div>
</div>
{/* Tag */}
<div className="col-span-6 md:col-span-2">
<span className="font-mono text-[10px] tracking-[0.15em] uppercase text-[#8A8480] border border-[#C8C2B8] px-3 py-1.5 group-hover:border-[#0A0A0A] group-hover:text-[#0A0A0A] transition-colors duration-200">
{study.tag}
</span>
</div>
{/* Description */}
<div className="col-span-12 md:col-span-4">
<p className="text-[#8A8480] text-[13px] leading-relaxed group-hover:text-[#6A6460] transition-colors">
{study.desc}
</p>
</div>
{/* Arrow */}
<div className="col-span-6 md:col-span-1 flex justify-end">
<motion.div
className="text-[#C8C2B8] group-hover:text-[#0A0A0A] transition-colors"
animate={{ x: hoverCase === idx ? 4 : 0 }}
>
<IconArrowUpRight />
</motion.div>
</div>
</div>
{/* Expanded tech stack */}
<AnimatePresence>
{hoverCase === idx && (
<motion.div
className="pb-6 flex flex-wrap gap-2 pl-0 md:pl-[calc(8.33%+1.5rem)]"
initial={{ height: 0, opacity: 0 }}
animate={{ height: "auto", opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
transition={{ duration: 0.25, ease: expo }}
>
<span className="font-mono text-[9px] tracking-[0.2em] uppercase text-[#C8C2B8] pr-3">STACK:</span>
{study.tech.map((t: string) => (
<span key={t} className="font-mono text-[9px] tracking-wider uppercase px-2.5 py-1 bg-[#EDE8E0] text-[#6A6460] border border-[#C8C2B8]">
{t}
</span>
))}
</motion.div>
)}
</AnimatePresence>
</motion.div>
))}
</div>
<motion.div
className="mt-12 flex justify-end"
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
>
<a href={`/${lang}/work`} className="btn-brutal inline-flex items-center gap-3 px-8 py-4 font-display font-black text-[12px] tracking-widest uppercase cursor-pointer">
{dict.work.analyzeBtn} <IconArrow />
</a>
</motion.div>
</div>
</section>
{/* ──────────────── PROCESS ──────────────── */}
<section id="process" className="py-24 border-b border-[#C8C2B8] bg-[#EDE8E0]">
<div className="max-w-7xl mx-auto px-6">
<div className="mb-20">
<Label>{dict.process.badge}</Label>
<h2 className="font-display font-black uppercase text-5xl sm:text-6xl lg:text-7xl leading-[0.9] tracking-tight">
<SplitReveal text={dict.process.title} />
</h2>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-px bg-[#C8C2B8]">
{processes.map((p: any, idx: number) => (
<motion.div
key={idx}
className="bg-[#EDE8E0] p-8 relative overflow-hidden group"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: idx * 0.12, duration: 0.6 }}
whileHover={{ backgroundColor: "#E8E3DA" }}
>
<div className="absolute top-0 right-0 font-display font-black text-[7rem] leading-none text-[#D8D3CA] select-none pointer-events-none">
{p.num}
</div>
<div className="relative z-10">
<motion.div
className="w-8 h-1 bg-[#FFE600] mb-8"
initial={{ scaleX: 0 }}
whileInView={{ scaleX: 1 }}
viewport={{ once: true }}
style={{ transformOrigin: "left" }}
transition={{ delay: idx * 0.12 + 0.3, duration: 0.5 }}
/>
<div className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] mb-4">
{p.timeframe}
</div>
<h3 className="font-display font-black text-lg uppercase text-[#0A0A0A] mb-4 group-hover:text-[#0A0A0A] transition-colors">
{p.title}
</h3>
<p className="text-[#7A7470] text-[13px] leading-relaxed">
{p.desc}
</p>
</div>
</motion.div>
))}
</div>
</div>
</section>
{/* ──────────────── BLOG FEATURED ──────────────── */}
<section id="blog" className="py-24 border-b border-[#C8C2B8]">
<div className="max-w-7xl mx-auto px-6">
<div className="flex flex-col md:flex-row md:items-end justify-between gap-8 mb-16">
<div>
<Label>{dict.blog.badge}</Label>
<h2 className="font-display font-black uppercase text-5xl sm:text-6xl leading-[0.9] tracking-tight">
<SplitReveal text={dict.blog.title} />
</h2>
</div>
<Link
href={`/${lang}/blog`}
className="font-mono text-[10px] tracking-[0.2em] uppercase text-[#0A0A0A] border-b-2 border-[#0A0A0A] pb-1 hover:text-[#FF4500] hover:border-[#FF4500] transition-colors self-start md:self-auto"
>
{dict.blog.viewAll}
</Link>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{featuredPosts.map((post, idx) => {
const content = post[lang] || post.en;
const accent = ["#FFE600", "#FF4500", "#00CC77"][idx] || "#FFE600";
return (
<motion.div
key={post.slug}
className="group flex flex-col bg-[#F4F0E8] border border-[#C8C2B8] hover:border-[#0A0A0A] p-8 relative overflow-hidden transition-all duration-300 h-full"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: idx * 0.1, duration: 0.6 }}
whileHover={{ y: -6, backgroundColor: "#EDE8E0", boxShadow: "4px 4px 0px 0px #0A0A0A" }}
>
<div className="flex items-center gap-3 mb-6">
<span
className="font-mono text-[9px] tracking-[0.2em] uppercase px-2.5 py-1 border border-[#C8C2B8] text-[#6A6460]"
style={{ borderLeftColor: accent, borderLeftWidth: 3 }}
>
{content.category}
</span>
<span className="font-mono text-[9px] text-[#A0998E]">
{post.date}
</span>
</div>
<h3 className="font-display font-black text-xl uppercase text-[#0A0A0A] mb-4 leading-tight group-hover:text-[#0A0A0A]">
{content.title}
</h3>
<p className="text-[#6A6460] text-[13px] leading-relaxed mb-8 flex-grow">
{content.excerpt}
</p>
<div className="pt-6 border-t border-[#C8C2B8] flex items-center justify-between mt-auto">
<div className="flex flex-col">
<span className="font-display font-black text-[11px] uppercase text-[#0A0A0A]">{post.author}</span>
<span className="font-mono text-[9px] text-[#A0998E] uppercase tracking-wider">{post.authorRole}</span>
</div>
<Link
href={`/${lang}/blog/${post.slug}`}
className="w-10 h-10 border border-[#C8C2B8] group-hover:border-[#0A0A0A] group-hover:bg-[#0A0A0A] group-hover:text-[#FFE600] text-[#0A0A0A] flex items-center justify-center transition-all"
>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<line x1="5" y1="12" x2="19" y2="12" />
<polyline points="12 5 19 12 12 19" />
</svg>
</Link>
</div>
{/* Top line category accent */}
<div className="absolute top-0 left-0 right-0 h-1 transition-colors" style={{ backgroundColor: accent }} />
</motion.div>
);
})}
</div>
</div>
</section>
{/* ──────────────── FAQ ──────────────── */}
<section id="faq" className="py-24 border-b border-[#C8C2B8] bg-[#EDE8E0]">
<div className="max-w-4xl mx-auto px-6">
<div className="mb-16">
<Label>{dict.faq.badge}</Label>
<h2 className="font-display font-black uppercase text-5xl sm:text-6xl leading-[0.9] tracking-tight">
<SplitReveal text={dict.faq.title} />
</h2>
</div>
<div>
{faqs.map((faq: any, idx: number) => (
<motion.div
key={idx}
className="border-b border-[#C8C2B8]"
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: idx * 0.06 }}
>
<button
className="w-full flex items-center justify-between py-6 text-left cursor-pointer group"
onClick={() => setActiveFaq(activeFaq === idx ? null : idx)}
>
<span className="font-display font-black text-base sm:text-lg uppercase text-[#0A0A0A] pr-8 leading-snug">
{faq.q}
</span>
<motion.div
className="flex-shrink-0 w-8 h-8 border border-[#C8C2B8] group-hover:border-[#0A0A0A] group-hover:bg-[#FFE600] text-[#8A8480] group-hover:text-[#0A0A0A] flex items-center justify-center transition-colors"
animate={{ rotate: activeFaq === idx ? 45 : 0 }}
>
<IconPlus />
</motion.div>
</button>
<AnimatePresence initial={false}>
{activeFaq === idx && (
<motion.div
initial={{ height: 0, opacity: 0 }}
animate={{ height: "auto", opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
transition={{ duration: 0.3, ease: expo }}
>
<p className="text-[#6A6460] text-[14px] leading-relaxed pb-6 border-l-2 border-[#FFE600] pl-6">
{faq.a}
</p>
</motion.div>
)}
</AnimatePresence>
</motion.div>
))}
</div>
</div>
</section>
{/* ──────────────── CONTACT ──────────────── */}
<section id="contact" className="py-24 border-b border-[#C8C2B8]">
<div className="max-w-7xl mx-auto px-6">
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12 mb-16">
<div className="lg:col-span-7">
<Label>{dict.contact.badge}</Label>
<h2 className="font-display font-black uppercase text-5xl sm:text-6xl lg:text-7xl leading-[0.9] tracking-tight">
<SplitReveal text={dict.contact.title} />
</h2>
</div>
<div className="lg:col-span-5 flex items-end">
<p className="text-[#6A6460] leading-relaxed border-l-2 border-[#FFE600] pl-6">
{dict.contact.desc}
</p>
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-12 gap-px bg-[#C8C2B8]">
{/* Form */}
<div className="lg:col-span-8 bg-[#F4F0E8] p-10">
<AnimatePresence mode="wait">
{!formSent ? (
<motion.form
key="form"
onSubmit={(e) => { e.preventDefault(); setFormSent(true); }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.3 }}
>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 mb-8">
{[
{ label: dict.contact.formName, placeholder: dict.contact.formNamePlaceholder, type: "text" },
{ label: dict.contact.formEmail, placeholder: dict.contact.formEmailPlaceholder, type: "email" },
{ label: dict.contact.formCompany, placeholder: dict.contact.formCompanyPlaceholder, type: "text" },
{ label: dict.contact.formTrack, type: "select", options: ["$5k $20k", "$20k $50k", "$50k $100k", "$100k+"] },
].map((field, fi) => (
<div key={fi} className="flex flex-col">
<label className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] mb-3">{field.label}</label>
{field.type === "select" ? (
<select className="bg-transparent border-b border-[#C8C2B8] focus:border-[#0A0A0A] text-[#0A0A0A] text-sm py-3 focus:outline-none transition-colors cursor-pointer appearance-none">
{field.options?.map(opt => <option key={opt} value={opt} className="bg-[#F4F0E8]">{opt}</option>)}
</select>
) : (
<input
required
type={field.type}
placeholder={field.placeholder}
className="bg-transparent border-b border-[#C8C2B8] focus:border-[#0A0A0A] text-[#0A0A0A] placeholder-[#C8C2B8] text-sm py-3 focus:outline-none transition-colors rounded-none"
/>
)}
</div>
))}
</div>
<div className="flex flex-col mb-8">
<label className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] mb-3">{dict.contact.formScope}</label>
<textarea
required
rows={4}
placeholder={dict.contact.formScopePlaceholder}
className="bg-transparent border-b border-[#C8C2B8] focus:border-[#0A0A0A] text-[#0A0A0A] placeholder-[#C8C2B8] text-sm py-3 focus:outline-none transition-colors resize-none rounded-none"
/>
</div>
<motion.button
type="submit"
className="btn-brutal btn-brutal-yellow w-full py-5 font-display font-black text-[13px] tracking-widest uppercase cursor-pointer"
whileTap={{ scale: 0.98 }}
>
{dict.contact.formSubmit}
</motion.button>
</motion.form>
) : (
<motion.div
key="success"
className="py-16 flex flex-col items-center text-center"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4 }}
>
<div className="w-16 h-16 bg-[#FFE600] border-2 border-[#0A0A0A] flex items-center justify-center mb-8">
<IconCheck />
</div>
<h3 className="font-display font-black text-3xl uppercase text-[#0A0A0A] mb-3">
{dict.contact.submittedTitle}
</h3>
<p className="text-[#6A6460] text-sm max-w-sm mb-8">
{dict.contact.submittedText}
</p>
<button
onClick={() => setFormSent(false)}
className="btn-brutal px-6 py-3 font-display font-black text-[11px] tracking-widest uppercase cursor-pointer"
>
{lang === "tr" ? "Yeni Talep" : "New Request"}
</button>
</motion.div>
)}
</AnimatePresence>
</div>
{/* Sidebar info */}
<div className="lg:col-span-4 bg-[#F4F0E8]">
<div className="border-b border-[#C8C2B8] p-8">
<div className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] mb-3">
{dict.contact.infoDirect}
</div>
<div className="font-display font-black text-base text-[#0A0A0A]">
hello@ayristech.com
</div>
</div>
<div className="border-b border-[#C8C2B8] p-8">
<div className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] mb-3">
{dict.contact.infoBlueprint}
</div>
<div className="font-display font-black text-base text-[#0A0A0A]">
+90 532 000 00 00
</div>
</div>
<div className="p-8">
<div className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] mb-3">
{lang === "tr" ? "Genel Merkez" : "HQ Coordinates"}
</div>
<div className="font-display font-black text-base text-[#0A0A0A]">
{dict.contact.infoBaseText}
</div>
</div>
{/* Yellow CTA block */}
<div className="bg-[#FFE600] p-8 border-t-2 border-[#0A0A0A]">
<p className="font-display font-black text-sm uppercase text-[#0A0A0A] leading-snug">
{lang === "tr"
? "Teknik ekibimiz 12 saat içinde geri döner."
: "Our team responds within 12 operational hours."}
</p>
</div>
</div>
</div>
</div>
</section>
<Footer lang={lang} dict={dict} />
</div>
);
}
+93
View File
@@ -0,0 +1,93 @@
"use client";
import { motion } from "framer-motion";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import type { Locale } from "@/i18n-config";
const expo = [0.16, 1, 0.3, 1] as [number, number, number, number];
export default function PartnersClient({
lang,
dict,
initialPartners,
}: {
lang: Locale;
dict: any;
initialPartners?: any[];
}) {
const partners = initialPartners && initialPartners.length > 0 ? initialPartners : (dict.partners.items as any[]);
return (
<div className="bg-[#F4F0E8] text-[#0A0A0A] font-body min-h-screen">
<Header lang={lang} dict={dict.nav} />
<main className="pt-32 pb-24 px-6 max-w-7xl mx-auto">
{/* Title Header Block */}
<div className="border-b border-[#C8C2B8] pb-12 mb-16">
<div className="flex items-center gap-3 mb-6">
<div className="w-3 h-3 bg-[#FFE600]" />
<span className="font-mono text-[10px] tracking-[0.3em] uppercase text-[#A0998E]">
{dict.partners.badge}
</span>
</div>
<motion.h1
className="font-display font-black text-5xl sm:text-6xl lg:text-8xl uppercase leading-[0.85] tracking-tight"
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, ease: expo }}
>
{dict.partners.title}
</motion.h1>
<p className="text-[#6A6460] mt-6 text-lg max-w-3xl font-light">
{dict.partners.desc}
</p>
</div>
{/* Dynamic partners brutalist card grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-px bg-[#C8C2B8] border border-[#C8C2B8]">
{partners.map((partner, idx) => (
<motion.div
key={partner.name}
className="group bg-[#F4F0E8] p-8 relative overflow-hidden transition-all duration-300 flex flex-col h-full cursor-default"
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: idx * 0.08 }}
whileHover={{ backgroundColor: "#EDE8E0" }}
>
{/* Monogram Badge */}
<div className="w-14 h-14 mb-8 border border-[#C8C2B8] group-hover:border-[#0A0A0A] group-hover:bg-[#0A0A0A] group-hover:text-[#FFE600] transition-all flex items-center justify-center font-display font-black text-sm text-[#8A8480] bg-[#F4F0E8] select-none">
{partner.mono}
</div>
{/* Title & Tag */}
<h3 className="font-display font-black text-xl uppercase text-[#0A0A0A] mb-1">
{partner.name}
</h3>
<p className="font-mono text-[9px] tracking-[0.2em] uppercase text-[#FF4500] mb-5 font-bold">
{partner.tag}
</p>
{/* Description */}
<p className="text-[#7A7470] text-[13px] leading-relaxed mb-8 flex-grow">
{partner.desc}
</p>
{/* Establishment Year details bar */}
<div className="pt-4 border-t border-[#C8C2B8] flex justify-between items-center mt-auto">
<span className="font-mono text-[9px] text-[#A0998E]">PARTNERSHIP</span>
<span className="font-mono text-[9px] text-[#0A0A0A] font-bold">[ EST. {partner.year} ]</span>
</div>
{/* Interactive bottom corner ribbon */}
<div className="absolute bottom-0 right-0 w-0 h-0 group-hover:w-8 group-hover:h-8 bg-[#FFE600] transition-all duration-300" />
</motion.div>
))}
</div>
</main>
<Footer lang={lang} dict={dict} />
</div>
);
}
+76
View File
@@ -0,0 +1,76 @@
"use client";
import { motion } from "framer-motion";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import type { Locale } from "@/i18n-config";
const expo = [0.16, 1, 0.3, 1] as [number, number, number, number];
export default function ProcessClient({ lang, dict }: { lang: Locale; dict: any }) {
const processes = dict.process.items as any[];
return (
<div className="bg-[#F4F0E8] text-[#0A0A0A] font-body min-h-screen">
<Header lang={lang} dict={dict.nav} />
<main className="pt-32 pb-24 px-6 max-w-7xl mx-auto">
<div className="border-b border-[#C8C2B8] pb-12 mb-16">
<div className="flex items-center gap-3 mb-6">
<div className="w-3 h-3 bg-[#FFE600]" />
<span className="font-mono text-[10px] tracking-[0.3em] uppercase text-[#A0998E]">{dict.process.badge}</span>
</div>
<motion.h1
className="font-display font-black text-5xl sm:text-6xl lg:text-8xl uppercase leading-[0.85] tracking-tight"
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, ease: expo }}
>
{dict.process.title}
</motion.h1>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-px bg-[#C8C2B8]">
{processes.map((p: any, idx: number) => (
<motion.div
key={idx}
className="group bg-[#F4F0E8] p-10 relative overflow-hidden"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: idx * 0.12, duration: 0.6 }}
whileHover={{ backgroundColor: "#EDE8E0" }}
>
<div className="absolute top-0 right-0 font-display font-black text-[7rem] leading-none text-[#E8E3DC] select-none pointer-events-none">
{p.num}
</div>
<div className="relative z-10">
<motion.div
className="w-8 h-1 bg-[#FFE600] mb-8"
initial={{ scaleX: 0 }}
whileInView={{ scaleX: 1 }}
viewport={{ once: true }}
style={{ transformOrigin: "left" }}
transition={{ delay: idx * 0.12 + 0.3, duration: 0.5 }}
/>
<div className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] mb-4">
{p.timeframe}
</div>
<h3 className="font-display font-black text-lg uppercase text-[#0A0A0A] mb-4 group-hover:text-[#0A0A0A]">
{p.title}
</h3>
<p className="text-[#7A7470] text-[13px] leading-relaxed">
{p.desc}
</p>
</div>
</motion.div>
))}
</div>
</main>
<Footer lang={lang} dict={dict} />
</div>
);
}
+144
View File
@@ -0,0 +1,144 @@
"use client";
import { motion } from "framer-motion";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import type { Locale } from "@/i18n-config";
const expo = [0.16, 1, 0.3, 1] as [number, number, number, number];
const IconAI = () => (
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.25" strokeLinecap="round" strokeLinejoin="round">
<rect x="3" y="3" width="18" height="18" rx="1" />
<path d="M9 3v18M15 3v18M3 9h18M3 15h18" />
<circle cx="9" cy="9" r="1.5" fill="currentColor" />
<circle cx="15" cy="15" r="1.5" fill="currentColor" />
</svg>
);
const IconChain = () => (
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.25" strokeLinecap="round" strokeLinejoin="round">
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" />
<path d="M3.27 6.96L12 12.01l8.73-5.05M12 22.08V12" />
</svg>
);
const IconMobile = () => (
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.25" strokeLinecap="round" strokeLinejoin="round">
<rect x="5" y="2" width="14" height="20" rx="2" />
<path d="M12 18h.01" />
</svg>
);
const IconWeb = () => (
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.25" strokeLinecap="round" strokeLinejoin="round">
<rect x="3" y="4" width="18" height="16" rx="1" />
<path d="M3 9h18M8 6h.01M11 6h.01M14 6h.01" />
</svg>
);
export default function ServicesClient({ lang, dict }: { lang: Locale; dict: any }) {
const services = [
{
icon: <IconAI />, title: dict.services.items.ai.title, code: "AI / ML", desc: dict.services.items.ai.desc, accent: "#FFE600",
items: lang === "tr"
? ["Tahmin Modelleri", "Doğal Dil İşleme", "Bilgisayarlı Görü", "Etmen İş Akışları", "Özel Gömme Uzayları", "RAG Sistemleri"]
: ["Predictive Models", "Natural Language Processing", "Computer Vision", "Agentic Workflows", "Custom Embeddings", "RAG Deployments"],
},
{
icon: <IconChain />, title: dict.services.items.blockchain.title, code: "BC / WEB3", desc: dict.services.items.blockchain.desc, accent: "#FF4500",
items: lang === "tr"
? ["Akıllı Sözleşme Denetimi", "DeFi Mimarileri", "Tokenomik Tasarımı", "Çapraz Zincir Köprüleri", "EVM Optimizasyonu", "IPFS Entegrasyonu"]
: ["Smart Contract Audit", "DeFi Architectures", "Tokenomics Design", "Cross-chain Bridges", "EVM Optimizations", "IPFS Integration"],
},
{
icon: <IconMobile />, title: dict.services.items.mobile.title, code: "MOB / DART", desc: dict.services.items.mobile.desc, accent: "#0A0A0A",
items: lang === "tr"
? ["Evrensel Kod Tabanı", "Çevrimdışı Senkronizasyon", "Biyometrik Protokoller", "Optimize Çekirdek Paket", "Push Bildirim Mimarisi", "Mağaza Operasyonları"]
: ["Universal Codebase", "Offline Syncing", "Biometric Protocols", "Optimized Core Bundle", "Push Notification Architecture", "App Store Operations"],
},
{
icon: <IconWeb />, title: dict.services.items.web.title, code: "WEB / NEXT", desc: dict.services.items.web.desc, accent: "#00CC77",
items: lang === "tr"
? ["Next.js App Router", "Sunucu Bileşenleri", "Headless E-Ticaret", "Modüler API Ağı", "Tailwind CSS Entegrasyonu", "Vercel Kenar Telemetrisi"]
: ["Next.js App Router", "Server Components", "Headless Commerce", "Modular API Mesh", "Tailwind CSS Integration", "Vercel Edge Telemetry"],
},
];
return (
<div className="bg-[#F4F0E8] text-[#0A0A0A] font-body min-h-screen">
<Header lang={lang} dict={dict.nav} />
<main className="pt-32 pb-24 px-6 max-w-7xl mx-auto">
<div className="border-b border-[#C8C2B8] pb-12 mb-16">
<div className="flex items-center gap-3 mb-6">
<div className="w-3 h-3 bg-[#FFE600]" />
<span className="font-mono text-[10px] tracking-[0.3em] uppercase text-[#A0998E]">{dict.services.badge}</span>
</div>
<motion.h1
className="font-display font-black text-5xl sm:text-6xl lg:text-8xl uppercase leading-[0.85] tracking-tight"
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, ease: expo }}
>
{dict.services.title}
</motion.h1>
</div>
<div className="grid grid-cols-1 gap-px bg-[#C8C2B8]">
{services.map((s, idx) => (
<motion.div
key={idx}
className="group bg-[#F4F0E8] grid grid-cols-1 lg:grid-cols-12 relative overflow-hidden"
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: idx * 0.1 }}
whileHover={{ backgroundColor: "#EDE8E0" }}
>
{/* Left */}
<div className="lg:col-span-5 p-10 border-b lg:border-b-0 lg:border-r border-[#C8C2B8] flex flex-col justify-between">
<div>
<div className="flex items-start justify-between mb-8">
<div className="w-14 h-14 border border-[#C8C2B8] group-hover:border-[#0A0A0A] group-hover:bg-[#0A0A0A] group-hover:text-[#FFE600] flex items-center justify-center text-[#8A8480] transition-colors duration-200">
{s.icon}
</div>
<span className="font-mono text-[9px] tracking-[0.25em] uppercase text-[#C8C2B8] group-hover:text-[#A0998E] transition-colors">
{s.code}
</span>
</div>
<h2 className="font-display font-black text-3xl uppercase mb-4 group-hover:text-[#0A0A0A]">
{s.title}
</h2>
<p className="text-[#7A7470] text-[14px] leading-relaxed">
{s.desc}
</p>
</div>
<div className="font-display font-black text-[6rem] leading-none text-[#E8E3DC] select-none mt-4">
{String(idx + 1).padStart(2, "0")}
</div>
</div>
{/* Right */}
<div className="lg:col-span-7 p-10 flex flex-col justify-center">
<div className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] mb-8">
{dict.services.deliverablesLabel}
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
{s.items.map((item: string) => (
<div key={item} className="flex items-center gap-4 group/item cursor-default">
<div className="w-1 h-4 flex-shrink-0 group-hover/item:h-6 transition-all duration-200" style={{ backgroundColor: s.accent }} />
<span className="font-display font-bold text-[14px] uppercase text-[#8A8480] group-hover/item:text-[#0A0A0A] transition-colors">
{item}
</span>
</div>
))}
</div>
</div>
</motion.div>
))}
</div>
</main>
<Footer lang={lang} dict={dict} />
</div>
);
}
+148
View File
@@ -0,0 +1,148 @@
"use client";
import { motion } from "framer-motion";
import { useState } from "react";
import Link from "next/link";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import type { Locale } from "@/i18n-config";
const expo = [0.16, 1, 0.3, 1] as [number, number, number, number];
const IconArrowUpRight = () => (
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<line x1="7" y1="17" x2="17" y2="7" />
<polyline points="7 7 17 7 17 17" />
</svg>
);
export default function WorkClient({
lang,
dict,
initialProjects,
}: {
lang: Locale;
dict: any;
initialProjects?: any[];
}) {
const [hoverCase, setHoverCase] = useState<number | null>(null);
const accentColors = ["#FFE600", "#FF4500", "#0A0A0A", "#00CC77"];
const projectsList = initialProjects && initialProjects.length > 0 ? initialProjects : (dict.work.items as any[]);
const caseStudies = projectsList.map((item: any, idx: number) => ({
...item,
accent: accentColors[idx % accentColors.length] ?? "#FFE600",
// Fallback tech in case older dict snapshot doesn't have it yet
tech: item.tech ?? ["React", "TypeScript", "Node.js"],
}));
return (
<div className="bg-[#F4F0E8] text-[#0A0A0A] font-body min-h-screen">
<Header lang={lang} dict={dict.nav} />
<main className="pt-32 pb-24 px-6 max-w-7xl mx-auto">
{/* Page header */}
<div className="border-b border-[#C8C2B8] pb-12 mb-16">
<div className="flex items-center gap-3 mb-6">
<div className="w-3 h-3 bg-[#FFE600]" />
<span className="font-mono text-[10px] tracking-[0.3em] uppercase text-[#A0998E]">
{dict.work.badge}
</span>
</div>
<motion.h1
className="font-display font-black text-5xl sm:text-6xl lg:text-8xl uppercase leading-[0.85] tracking-tight"
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, ease: expo }}
>
{dict.work.title}
</motion.h1>
</div>
{/* Case study list */}
<div className="space-y-px bg-[#C8C2B8]">
{caseStudies.map((study: any, idx: number) => (
<motion.div
key={idx}
className="group bg-[#F4F0E8] grid grid-cols-1 lg:grid-cols-12 relative overflow-hidden cursor-pointer"
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: idx * 0.1 }}
whileHover={{ backgroundColor: "#EDE8E0" }}
onHoverStart={() => setHoverCase(idx)}
onHoverEnd={() => setHoverCase(null)}
>
{/* Full-card link */}
<Link
href={`/${lang}/work/${study.slug}`}
className="absolute inset-0 z-10"
aria-label={study.title}
/>
{/* Accent top bar */}
<motion.div
className="absolute top-0 left-0 right-0 h-1"
style={{ backgroundColor: study.accent }}
initial={{ scaleX: 0 }}
animate={{ scaleX: hoverCase === idx ? 1 : 0 }}
transition={{ duration: 0.3, ease: expo }}
/>
{/* Left column */}
<div className="lg:col-span-4 p-10 border-b lg:border-b-0 lg:border-r border-[#C8C2B8] flex flex-col justify-between">
<div>
<span className="font-mono text-[9px] tracking-[0.25em] uppercase text-[#A0998E] border border-[#C8C2B8] px-2.5 py-1">
{study.tag}
</span>
<h2 className="font-display font-black text-2xl uppercase mt-6 mb-2">
{study.title}
</h2>
</div>
<div>
<div className="font-mono text-[9px] tracking-[0.2em] uppercase text-[#A0998E] mb-1">
{dict.work.specsLabel}:
</div>
<div className="font-display font-bold text-[13px] text-[#0A0A0A]">
{study.spec}
</div>
<div className="font-display font-black text-[5rem] leading-none text-[#E8E3DC] select-none mt-4">
{study.num}
</div>
</div>
</div>
{/* Right column */}
<div className="lg:col-span-8 p-10 flex flex-col justify-between">
<p className="text-[#7A7470] text-base leading-relaxed mb-8">
{study.desc}
</p>
<div className="flex flex-wrap items-center justify-between gap-4 pt-6 border-t border-[#D8D3CA]">
<div className="flex flex-wrap gap-2">
{(study.tech as string[]).map((t) => (
<span
key={t}
className="font-mono text-[10px] tracking-wider uppercase px-2.5 py-1 border border-[#C8C2B8] text-[#8A8480] group-hover:border-[#0A0A0A] group-hover:text-[#0A0A0A] transition-colors"
>
{t}
</span>
))}
</div>
{/* Button sits above the overlay link via z-20 */}
<span className="relative z-20 font-display font-black text-[12px] uppercase tracking-wider text-[#0A0A0A] flex items-center gap-2 group-hover:opacity-60 transition-opacity">
{dict.work.analyzeBtn} <IconArrowUpRight />
</span>
</div>
</div>
</motion.div>
))}
</div>
</main>
<Footer lang={lang} dict={dict} />
</div>
);
}
+555
View File
@@ -0,0 +1,555 @@
"use client";
import { motion, useScroll, useTransform, AnimatePresence } from "framer-motion";
import { useRef, useState, useEffect } from "react";
import Link from "next/link";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import type { Locale } from "@/i18n-config";
const expo: [number, number, number, number] = [0.16, 1, 0.3, 1];
const IconArrowLeft = () => (
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<line x1="19" y1="12" x2="5" y2="12" />
<polyline points="12 19 5 12 12 5" />
</svg>
);
const IconArrowRight = () => (
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<line x1="5" y1="12" x2="19" y2="12" />
<polyline points="12 5 19 12 12 19" />
</svg>
);
const IconCheck = () => (
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#0A0A0A" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<polyline points="20 6 9 17 4 12" />
</svg>
);
// Tag colors per category
const accentFor = (tag: string): string => {
if (/ai|yz|ml/i.test(tag)) return "#FFE600";
if (/web3|blockchain|chain/i.test(tag)) return "#FF4500";
if (/mobile|mobil/i.test(tag)) return "#0A0A0A";
return "#00CC77";
};
interface Props {
lang: Locale;
dict: any;
project: any;
prev: any | null;
next: any | null;
}
const screenshotsFor = (slug: string): string[] => {
const mapping: Record<string, string[]> = {
"financeai-dashboard": [
"https://images.unsplash.com/photo-1551288049-bebda4e38f71?auto=format&fit=crop&w=1200&q=80",
"https://images.unsplash.com/photo-1460925895917-afdab827c52f?auto=format&fit=crop&w=1200&q=80",
"https://images.unsplash.com/photo-1551836022-d5d88e9218df?auto=format&fit=crop&w=1200&q=80",
],
"chainsupply-network": [
"https://images.unsplash.com/photo-1508873535684-277a3cbcc4e8?auto=format&fit=crop&w=1200&q=80",
"https://images.unsplash.com/photo-1639762681485-074b7f938ba0?auto=format&fit=crop&w=1200&q=80",
"https://images.unsplash.com/photo-1504384308090-c894fdcc538d?auto=format&fit=crop&w=1200&q=80",
],
"meditrack-mobile": [
"https://images.unsplash.com/photo-1576091160399-112ba8d25d1d?auto=format&fit=crop&w=1200&q=80",
"https://images.unsplash.com/photo-1584982751601-97dcc096659c?auto=format&fit=crop&w=1200&q=80",
"https://images.unsplash.com/photo-1530026405186-ed1ea0ac7a63?auto=format&fit=crop&w=1200&q=80",
],
"novamart-platform": [
"https://images.unsplash.com/photo-1460925895917-afdab827c52f?auto=format&fit=crop&w=1200&q=80",
"https://images.unsplash.com/photo-1556742049-0cfed4f6a45d?auto=format&fit=crop&w=1200&q=80",
"https://images.unsplash.com/photo-1523474253046-8cd2748b5fd2?auto=format&fit=crop&w=1200&q=80",
],
};
return mapping[slug] || [];
};
export default function WorkDetailClient({ lang, dict, project, prev, next }: Props) {
const heroRef = useRef<HTMLDivElement>(null);
const { scrollYProgress } = useScroll({ target: heroRef, offset: ["start start", "end start"] });
const heroY = useTransform(scrollYProgress, [0, 1], ["0%", "30%"]);
const [activeImage, setActiveImage] = useState<string | null>(null);
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "Escape") setActiveImage(null);
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, []);
const accent = accentFor(project.tag);
let screenshots = screenshotsFor(project.slug);
if (project.gallery && project.gallery.length > 0) {
screenshots = project.gallery;
}
return (
<div className="bg-[#F4F0E8] text-[#0A0A0A] font-body min-h-screen">
<Header lang={lang} dict={dict.nav} />
{/* ── HERO ── */}
<section
ref={heroRef}
className="relative min-h-[70vh] flex flex-col justify-end overflow-hidden border-b border-[#C8C2B8]"
>
{/* Dot grid */}
<motion.div
className="absolute inset-0"
style={{ y: heroY }}
>
{project.image ? (
<>
<div
className="absolute inset-0 bg-cover bg-center"
style={{ backgroundImage: `url(${project.image})` }}
/>
<div className="absolute inset-0 bg-[#F4F0E8]/80" />
</>
) : (
<div className="absolute inset-0 dot-grid opacity-50" />
)}
</motion.div>
{/* Accent left vertical bar */}
<div className="absolute top-0 left-0 w-1 h-full" style={{ backgroundColor: accent }} />
{/* Big number watermark */}
<motion.div
className="absolute right-0 bottom-0 font-display font-black select-none pointer-events-none text-[#E8E3DC] leading-none"
style={{ fontSize: "clamp(8rem, 25vw, 20rem)" }}
initial={{ opacity: 0, x: 40 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 1, delay: 0.3 }}
>
{project.num}
</motion.div>
<div className="relative z-10 max-w-7xl mx-auto px-6 w-full pb-16 pt-36">
{/* Breadcrumb */}
<motion.div
className="flex items-center gap-3 mb-10"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.1 }}
>
<Link
href={`/${lang}/work`}
className="flex items-center gap-2 font-mono text-[10px] tracking-[0.25em] uppercase text-[#A0998E] hover:text-[#0A0A0A] transition-colors"
>
<IconArrowLeft /> {dict.nav.work}
</Link>
<span className="text-[#C8C2B8]">/</span>
<span className="font-mono text-[10px] tracking-[0.25em] uppercase text-[#0A0A0A]">
{project.num}
</span>
</motion.div>
{/* Tag badge */}
<motion.div
className="mb-5"
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2, duration: 0.5 }}
>
<span
className="inline-block font-mono text-[10px] tracking-[0.25em] uppercase px-3 py-1.5 border border-[#C8C2B8]"
style={{ borderLeftColor: accent, borderLeftWidth: 3 }}
>
{project.tag}
</span>
</motion.div>
{/* Title */}
<div className="overflow-hidden mb-8">
<motion.h1
className="font-display font-black uppercase leading-[0.85] tracking-tight text-[#0A0A0A]"
style={{ fontSize: "clamp(3rem, 8vw, 7rem)" }}
initial={{ y: "110%" }}
animate={{ y: 0 }}
transition={{ duration: 0.85, ease: expo, delay: 0.25 }}
>
{project.title}
</motion.h1>
</div>
{/* Meta row */}
<motion.div
className="grid grid-cols-2 md:grid-cols-4 gap-px bg-[#C8C2B8] border-t border-[#C8C2B8]"
initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.5, duration: 0.6 }}
>
{[
{ label: lang === "tr" ? "Yıl" : "Year", value: project.year },
{ label: lang === "tr" ? "Süre" : "Duration", value: project.duration },
{ label: lang === "tr" ? "Sektör" : "Sector", value: project.tag },
{ label: lang === "tr" ? "Müşteri" : "Client", value: project.client },
].map((m, i) => (
<div key={i} className="bg-[#F4F0E8] px-5 py-4">
<div className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] mb-1">{m.label}</div>
<div className="font-display font-black text-[13px] uppercase text-[#0A0A0A] truncate">{m.value}</div>
</div>
))}
</motion.div>
</div>
</section>
{/* ── CONTENT ── */}
<main className="max-w-7xl mx-auto px-6 py-20">
<div className="grid grid-cols-1 lg:grid-cols-12 gap-16">
{/* Left column: main content */}
<div className="lg:col-span-8 space-y-20">
{/* Overview */}
<motion.section
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.7 }}
>
<div className="flex items-center gap-3 mb-6">
<div className="w-4 h-4 flex-shrink-0" style={{ backgroundColor: accent }} />
<span className="font-mono text-[10px] tracking-[0.3em] uppercase text-[#A0998E]">
{lang === "tr" ? "Genel Bakış" : "Overview"}
</span>
<div className="flex-1 h-px bg-[#C8C2B8]" />
</div>
<p className="text-[#4A4440] text-lg leading-relaxed border-l-4 pl-6" style={{ borderColor: accent }}>
{project.desc}
</p>
</motion.section>
{/* Challenge */}
<motion.section
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.7 }}
>
<div className="flex items-center gap-3 mb-6">
<div className="w-4 h-4 border-2 border-[#0A0A0A] flex-shrink-0" />
<span className="font-mono text-[10px] tracking-[0.3em] uppercase text-[#A0998E]">
{lang === "tr" ? "Problem" : "The Challenge"}
</span>
<div className="flex-1 h-px bg-[#C8C2B8]" />
</div>
<h2 className="font-display font-black text-2xl uppercase text-[#0A0A0A] mb-4">
{lang === "tr" ? "Ne Sorununu Çözdük?" : "What Problem Did We Solve?"}
</h2>
<p className="text-[#6A6460] leading-relaxed">
{project.challenge}
</p>
</motion.section>
{/* Solution */}
<motion.section
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.7 }}
>
<div className="flex items-center gap-3 mb-6">
<div className="w-4 h-4 border-2 flex-shrink-0" style={{ borderColor: accent }} />
<span className="font-mono text-[10px] tracking-[0.3em] uppercase text-[#A0998E]">
{lang === "tr" ? "Çözüm" : "Our Solution"}
</span>
<div className="flex-1 h-px bg-[#C8C2B8]" />
</div>
<h2 className="font-display font-black text-2xl uppercase text-[#0A0A0A] mb-4">
{lang === "tr" ? "Nasıl İnşa Ettik?" : "How Did We Build It?"}
</h2>
<p className="text-[#6A6460] leading-relaxed">
{project.solution}
</p>
</motion.section>
{/* Results */}
<motion.section
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.7 }}
>
<div className="flex items-center gap-3 mb-8">
<div className="w-4 h-4 flex-shrink-0" style={{ backgroundColor: accent }} />
<span className="font-mono text-[10px] tracking-[0.3em] uppercase text-[#A0998E]">
{lang === "tr" ? "Sonuçlar" : "Results"}
</span>
<div className="flex-1 h-px bg-[#C8C2B8]" />
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-px bg-[#C8C2B8]">
{project.results.map((r: string, idx: number) => (
<motion.div
key={idx}
className="bg-[#F4F0E8] p-6 flex items-start gap-4 group"
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: idx * 0.1 }}
whileHover={{ backgroundColor: "#EDE8E0" }}
>
<div
className="w-6 h-6 flex-shrink-0 flex items-center justify-center mt-0.5"
style={{ backgroundColor: accent }}
>
<IconCheck />
</div>
<p className="font-display font-bold text-[14px] uppercase text-[#0A0A0A] leading-snug">
{r}
</p>
</motion.div>
))}
</div>
</motion.section>
</div>
{/* Right column: sidebar */}
<aside className="lg:col-span-4 space-y-0">
<div className="sticky top-24">
{/* Perf spec */}
<motion.div
className="border border-[#C8C2B8] mb-px"
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.4 }}
>
<div className="border-b border-[#C8C2B8] px-6 py-3 flex items-center gap-2">
<div className="w-2 h-2" style={{ backgroundColor: accent }} />
<span className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E]">
{dict.work.specsLabel}
</span>
</div>
<div className="px-6 py-5">
<p className="font-display font-black text-sm uppercase text-[#0A0A0A] leading-snug">
{project.spec}
</p>
</div>
</motion.div>
{/* Tech stack */}
<motion.div
className="border border-[#C8C2B8] mb-px"
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.5 }}
>
<div className="border-b border-[#C8C2B8] px-6 py-3">
<span className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E]">
{lang === "tr" ? "Teknoloji Yığını" : "Tech Stack"}
</span>
</div>
<div className="px-6 py-5 flex flex-wrap gap-2">
{project.tech.map((t: string) => (
<span
key={t}
className="font-mono text-[10px] tracking-wider uppercase px-2.5 py-1.5 border border-[#C8C2B8] text-[#6A6460] hover:border-[#0A0A0A] hover:text-[#0A0A0A] transition-colors cursor-default"
>
{t}
</span>
))}
</div>
</motion.div>
{/* Website */}
{project.website && (
<motion.div
className="border border-[#C8C2B8] mb-px"
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.55 }}
>
<div className="border-b border-[#C8C2B8] px-6 py-3 flex items-center gap-2">
<div className="w-2 h-2" style={{ backgroundColor: accent }} />
<span className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E]">
{lang === "tr" ? "Canlı Proje" : "Live Project"}
</span>
</div>
<div className="px-6 py-5">
<a
href={project.website.startsWith('http') ? project.website : `https://${project.website}`}
target="_blank"
rel="noopener noreferrer"
className="inline-block font-mono text-[10px] tracking-wider uppercase px-4 py-2 border border-[#0A0A0A] hover:bg-[#0A0A0A] hover:text-[#FFE600] transition-colors cursor-pointer w-full text-center"
>
{lang === "tr" ? "Siteyi Ziyaret Et" : "Visit Website"}
</a>
</div>
</motion.div>
)}
{/* CTA */}
<motion.div
className="border-2 border-[#0A0A0A] p-6"
style={{ backgroundColor: accent }}
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.6 }}
>
<p className="font-display font-black text-sm uppercase text-[#0A0A0A] mb-4 leading-snug">
{lang === "tr" ? "Benzer bir proje mi istiyorsunuz?" : "Want a similar project?"}
</p>
<Link
href={`/${lang}/contact`}
className="btn-brutal inline-flex items-center gap-2 px-5 py-3 font-display font-black text-[11px] tracking-widest uppercase cursor-pointer bg-[#0A0A0A] text-[#F4F0E8] border-[#0A0A0A]"
>
{dict.nav.quote} <IconArrowRight />
</Link>
</motion.div>
</div>
</aside>
</div>
</main>
{/* ── PROJECT SCREENSHOTS GALLERY ── */}
{screenshots.length > 0 && (
<section className="py-24 border-t border-[#C8C2B8] bg-[#EDE8E0]">
<div className="max-w-7xl mx-auto px-6">
<div className="flex items-center gap-3 mb-12">
<div className="w-3 h-3" style={{ backgroundColor: accent }} />
<span className="font-mono text-[10px] tracking-[0.3em] uppercase text-[#A0998E]">
{dict.work.galleryTitle || "EKRAN GÖRÜNTÜLERİ"}
</span>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{screenshots.map((src, idx) => (
<motion.div
key={idx}
className="group bg-[#F4F0E8] border border-[#C8C2B8] hover:border-[#0A0A0A] p-3 relative overflow-hidden transition-all duration-300 cursor-zoom-in"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: idx * 0.1, duration: 0.6 }}
onClick={() => setActiveImage(src)}
whileHover={{ y: -6, boxShadow: `4px 4px 0px 0px ${accent}` }}
>
<div className="aspect-[16/10] w-full overflow-hidden border border-[#C8C2B8] group-hover:border-[#0A0A0A] bg-[#EDE8E0] transition-colors relative">
<img
src={src}
alt={`${project.title} screenshot ${idx + 1}`}
className="w-full h-full object-cover grayscale group-hover:grayscale-0 contrast-[1.1] brightness-[0.98] group-hover:scale-105 transition-all duration-700"
/>
<div className="absolute inset-0 bg-[#0A0A0A]/5 opacity-100 group-hover:opacity-0 transition-opacity duration-300" />
</div>
<div className="mt-3 flex justify-between items-center font-mono text-[9px] text-[#A0998E] group-hover:text-[#0A0A0A] transition-colors">
<span>SCREEN // 0{idx + 1}</span>
<span className="uppercase tracking-widest">[ ZOOM ]</span>
</div>
</motion.div>
))}
</div>
</div>
</section>
)}
{/* Lightbox Modal */}
<AnimatePresence>
{activeImage && (
<motion.div
className="fixed inset-0 z-[100] flex items-center justify-center bg-black/85 backdrop-blur-md px-6 cursor-zoom-out"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={() => setActiveImage(null)}
>
<button
onClick={() => setActiveImage(null)}
className="absolute top-6 right-6 w-12 h-12 border border-white/20 hover:border-white/80 hover:bg-white/10 text-white flex items-center justify-center font-mono text-[10px] uppercase tracking-widest cursor-pointer transition-colors duration-200"
>
[ CLOSE ]
</button>
<motion.div
className="max-w-5xl max-h-[85vh] border-2 border-white/10 bg-[#0A0A0A] p-2 relative"
initial={{ scale: 0.9, y: 20 }}
animate={{ scale: 1, y: 0 }}
exit={{ scale: 0.9, y: 20 }}
transition={{ duration: 0.4, ease: expo }}
onClick={(e) => e.stopPropagation()}
>
<img
src={activeImage}
alt="Enlarged project screenshot"
className="max-w-full max-h-[80vh] object-contain block"
/>
</motion.div>
</motion.div>
)}
</AnimatePresence>
{/* ── PREV / NEXT NAVIGATION ── */}
<div className="border-t border-[#C8C2B8]">
<div className="max-w-7xl mx-auto grid grid-cols-1 md:grid-cols-2 gap-px bg-[#C8C2B8]">
{/* Prev */}
<div>
{prev ? (
<Link
href={`/${lang}/work/${prev.slug}`}
className="group flex flex-col p-10 bg-[#F4F0E8] hover:bg-[#EDE8E0] transition-colors h-full"
>
<div className="flex items-center gap-2 font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] group-hover:text-[#0A0A0A] transition-colors mb-4">
<IconArrowLeft />
{lang === "tr" ? "Önceki Proje" : "Previous Project"}
</div>
<div className="font-display font-black text-xl uppercase text-[#0A0A0A] mt-auto">
{prev.title}
</div>
<div className="font-mono text-[10px] tracking-wider uppercase text-[#A0998E] mt-1">
{prev.tag}
</div>
</Link>
) : (
<div className="p-10 bg-[#EDE8E0]" />
)}
</div>
{/* Next */}
<div>
{next ? (
<Link
href={`/${lang}/work/${next.slug}`}
className="group flex flex-col items-end p-10 bg-[#F4F0E8] hover:bg-[#EDE8E0] transition-colors h-full text-right"
>
<div className="flex items-center gap-2 font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] group-hover:text-[#0A0A0A] transition-colors mb-4">
{lang === "tr" ? "Sonraki Proje" : "Next Project"}
<IconArrowRight />
</div>
<div className="font-display font-black text-xl uppercase text-[#0A0A0A] mt-auto">
{next.title}
</div>
<div className="font-mono text-[10px] tracking-wider uppercase text-[#A0998E] mt-1">
{next.tag}
</div>
</Link>
) : (
<Link
href={`/${lang}/work`}
className="group flex flex-col items-end p-10 bg-[#F4F0E8] hover:bg-[#EDE8E0] transition-colors h-full text-right"
>
<div className="flex items-center gap-2 font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] group-hover:text-[#0A0A0A] transition-colors mb-4">
{lang === "tr" ? "Tüm Projeler" : "All Projects"}
<IconArrowRight />
</div>
<div className="font-display font-black text-xl uppercase text-[#C8C2B8] mt-auto">
{lang === "tr" ? "Portfolyo" : "Portfolio"}
</div>
</Link>
)}
</div>
</div>
</div>
<Footer lang={lang} dict={dict} />
</div>
);
}
+474
View File
@@ -0,0 +1,474 @@
"use client";
import { motion, useScroll, useTransform, AnimatePresence } from "framer-motion";
import { useRef, useState } from "react";
import type { DemoData } from "@/data/demos";
import AnimatedCounter from "@/components/ui/AnimatedCounter";
const easeOutExpo = [0.16, 1, 0.3, 1] as [number, number, number, number];
const fadeUp = {
hidden: { opacity: 0, y: 40 },
show: { opacity: 1, y: 0, transition: { duration: 0.7, ease: easeOutExpo } },
};
const stagger = {
hidden: {},
show: { transition: { staggerChildren: 0.1 } },
};
export default function DentalTemplate({ data }: { data: DemoData }) {
const { firma, istatistikler, hizmetler, projeler = [], yorumlar = [] } = data;
const heroRef = useRef<HTMLDivElement>(null);
const { scrollYProgress } = useScroll({ target: heroRef, offset: ["start start", "end start"] });
const heroY = useTransform(scrollYProgress, [0, 1], ["0%", "20%"]);
const heroOpacity = useTransform(scrollYProgress, [0, 0.8], [1, 0]);
const [activeYorum, setActiveYorum] = useState(0);
const [menuOpen, setMenuOpen] = useState(false);
const [showBookingModal, setShowBookingModal] = useState(false);
return (
<div className="bg-[#FAF7F2] text-[#1E2E38] font-body">
{/* ── HEADER ── */}
<motion.header
className="fixed top-0 left-0 right-0 z-50 px-6 py-4"
initial={{ y: -80 }}
animate={{ y: 0 }}
transition={{ duration: 0.6, ease: easeOutExpo }}
>
<div className="mx-auto max-w-6xl flex items-center justify-between h-16 px-6 bg-white/40 backdrop-blur-md rounded-3xl border border-white/20 shadow-sm">
<div className="flex items-center gap-2.5">
<span className="text-xl font-bold tracking-tight text-[#1E2E38] font-display flex items-center gap-1.5 uppercase">
<span className="text-2xl">🦷</span> {firma.adi}
</span>
</div>
<div className="flex items-center gap-8">
<button
className="flex flex-col gap-1.5 p-2 bg-[#1E2E38]/5 hover:bg-[#1E2E38]/10 transition-colors rounded-xl"
onClick={() => setMenuOpen(!menuOpen)}
>
<div className="w-5 h-0.5 bg-[#1E2E38]" />
<div className="w-3 h-0.5 bg-[#1E2E38]" />
</button>
</div>
<div className="hidden md:flex items-center gap-6">
<a href={`tel:${firma.telefon}`} className="text-xs font-bold text-[#1E2E38]/80 hover:text-[#1E2E38] transition-colors">
📞 {firma.telefon}
</a>
<motion.button
onClick={() => setShowBookingModal(true)}
className="text-xs font-black text-[#FAF7F2] bg-[#1E2E38] px-5 py-2.5 rounded-full hover:bg-[#121C22] transition-colors"
whileHover={{ scale: 1.04 }}
whileTap={{ scale: 0.97 }}
>
Contact Us
</motion.button>
</div>
</div>
{/* Dropdown Menu */}
<AnimatePresence>
{menuOpen && (
<motion.div
className="absolute top-24 left-6 right-6 bg-white/95 backdrop-blur-xl border border-gray-100 rounded-3xl p-6 shadow-2xl flex flex-col gap-4 z-50 md:max-w-md md:left-auto md:right-6"
initial={{ opacity: 0, y: -20, scale: 0.95 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: -20, scale: 0.95 }}
transition={{ duration: 0.25 }}
>
<h4 className="text-xs font-black uppercase tracking-widest text-gray-400 border-b pb-2 mb-2">Navigasyon</h4>
{[
{ label: "001 - Uyelik Programı", href: "#uyelik" },
{ label: "002 - Hizmetler", href: "#hizmetler" },
{ label: "003 - Portfolyo (Works)", href: "#works" },
{ label: "004 - Yorumlar", href: "#yorumlar" },
{ label: "005 - Randevu Al", href: "#randevu" }
].map(item => (
<a
key={item.href}
href={item.href}
onClick={() => setMenuOpen(false)}
className="font-display font-bold text-[#1E2E38] hover:text-[#D4AF37] transition-colors text-base"
>
{item.label}
</a>
))}
</motion.div>
)}
</AnimatePresence>
</motion.header>
{/* ── HERO SECTION ── */}
<section ref={heroRef} className="relative min-h-screen flex items-center overflow-hidden bg-[#FAF7F2] pt-24">
<div className="absolute inset-0 pointer-events-none z-10">
<div className="absolute top-[25%] left-[8%] text-[#1E2E38]/20 text-3xl font-light select-none">+</div>
<div className="absolute bottom-[20%] left-[28%] text-[#1E2E38]/20 text-3xl font-light select-none">+</div>
<div className="absolute bottom-[35%] right-[5%] text-[#1E2E38]/30 text-3xl font-light select-none">+</div>
</div>
<div className="relative z-10 max-w-6xl mx-auto px-6 w-full py-12">
<div className="grid lg:grid-cols-12 gap-12 items-center">
<motion.div
className="lg:col-span-12 z-20 text-center"
variants={stagger}
initial="hidden"
animate="show"
>
<motion.div
variants={fadeUp}
className="inline-flex items-center gap-2 text-[11px] font-black uppercase tracking-widest text-[#1E2E38]/60 mb-6"
>
<span className="w-1.5 h-1.5 rounded-full bg-[#1E2E38]" />
{firma.slogan}
</motion.div>
<motion.h1
variants={fadeUp}
className="text-6xl md:text-7xl font-display font-black text-[#1E2E38] leading-[1.05] tracking-tight mb-8"
>
Seamless 🦷
<br />
<span className="italic font-light opacity-90 text-[#3C5A48]">Dental Care</span>
</motion.h1>
<motion.p
variants={fadeUp}
className="text-[#1E2E38]/70 text-lg leading-relaxed max-w-md mx-auto mb-10 font-medium"
>
A smooth and hassle-free dental care experience for a healthy and confident smile.
</motion.p>
<motion.div variants={fadeUp}>
<motion.button
onClick={() => setShowBookingModal(true)}
className="inline-flex items-center gap-3 px-8 py-4 rounded-full bg-[#1E2E38] hover:bg-[#121C22] text-[#FAF7F2] font-black text-sm transition-all"
whileHover={{ scale: 1.04, boxShadow: "0 10px 30px rgba(30, 46, 56, 0.15)" }}
whileTap={{ scale: 0.97 }}
>
Book Now <span className="text-xs"></span>
</motion.button>
</motion.div>
</motion.div>
</div>
</div>
</section>
{/* ── SECTION 001: SAVINGS BENTO ── */}
<section id="uyelik" className="py-24 bg-[#FAF7F2] px-6 border-t border-[#1E2E38]/5">
<div className="max-w-6xl mx-auto">
<div className="grid lg:grid-cols-12 gap-16 items-start">
<motion.div
className="lg:col-span-5"
initial="hidden"
whileInView="show"
viewport={{ once: true, amount: 0.2 }}
variants={stagger}
>
<span className="inline-block text-[11px] font-black uppercase tracking-widest text-[#1E2E38]/60 mb-4">
001 - Join Membership
</span>
<h2 className="text-4xl lg:text-5xl font-display font-black text-[#1E2E38] leading-tight mb-6">
Affordable Dental Care for Your Family
</h2>
<p className="text-[#1E2E38]/70 text-base leading-relaxed mb-10">
Unlock optimal dental wellness for your loved ones. Get massive savings on check-ups, cleaning, and specialized cosmetic treatments.
</p>
<motion.button
onClick={() => setShowBookingModal(true)}
className="px-7 py-3.5 rounded-full bg-[#1E2E38] hover:bg-[#121C22] text-[#FAF7F2] font-black text-xs transition-colors"
whileHover={{ scale: 1.04 }}
whileTap={{ scale: 0.97 }}
>
Join Membership <span className="text-[10px]"></span>
</motion.button>
</motion.div>
<div className="lg:col-span-7 grid md:grid-cols-2 gap-6 w-full">
<motion.div
className="bg-[#EBF5F0] rounded-[36px] p-8 flex flex-col justify-between h-[320px] relative overflow-hidden group shadow-sm"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6 }}
whileHover={{ y: -6 }}
>
<div className="flex justify-between items-start">
<span className="text-5xl font-black text-[#1E2E38] font-display">
{istatistikler[0]?.deger}
</span>
<span className="text-3xl font-light text-[#1E2E38]/50 shrink-0 select-none">+</span>
</div>
<p className="text-[#1E2E38]/80 text-[13px] leading-relaxed font-medium">
{istatistikler[0]?.etiket}
</p>
</motion.div>
<motion.div
className="bg-[#1E2E38] rounded-[36px] p-8 flex flex-col justify-between h-[320px] relative overflow-hidden group shadow-xl"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: 0.15 }}
whileHover={{ y: -6 }}
>
<div className="flex justify-between items-start">
<span className="text-5xl font-black text-[#FAF7F2] font-display">
{istatistikler[1]?.deger}
</span>
<span className="text-3xl font-light text-[#FAF7F2]/50 shrink-0 select-none">+</span>
</div>
<p className="text-[#FAF7F2]/80 text-[13px] leading-relaxed font-medium">
{istatistikler[1]?.etiket}
</p>
</motion.div>
</div>
</div>
</div>
</section>
{/* ── CORE SERVICES CARD ROW ── */}
<section id="hizmetler" className="py-16 bg-white px-6">
<div className="max-w-6xl mx-auto">
<div className="grid md:grid-cols-3 gap-6">
{hizmetler.map((h, i) => (
<motion.div
key={i}
className="bg-[#FAF7F2]/60 hover:bg-[#FAF7F2] rounded-[28px] p-8 border border-gray-100 hover:border-[#1E2E38]/10 transition-all duration-300 flex flex-col items-center text-center group cursor-default"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: i * 0.1 }}
whileHover={{ y: -4 }}
>
<div className="w-14 h-14 rounded-full bg-white flex items-center justify-center text-2xl shadow-sm mb-5 transition-transform group-hover:scale-110">
{h.ikon}
</div>
<h3 className="font-display font-bold text-[#1E2E38] text-base mb-3 leading-snug">
{h.baslik}
</h3>
<p className="text-gray-400 text-xs leading-relaxed">
{h.aciklama}
</p>
</motion.div>
))}
</div>
</div>
</section>
{/* ── SECTION 002: OUR WORKS ── */}
<section id="works" className="py-24 bg-[#EBF5F0] px-6">
<div className="max-w-6xl mx-auto">
<div className="flex flex-col md:flex-row md:items-end justify-between mb-16 gap-6">
<motion.div
initial="hidden"
whileInView="show"
viewport={{ once: true }}
variants={stagger}
>
<span className="inline-block text-[11px] font-black uppercase tracking-widest text-[#1E2E38]/60 mb-4">
002 - Our Works
</span>
<h2 className="text-4xl lg:text-5xl font-display font-black text-[#1E2E38] leading-tight">
A Healthy Smile<br />Starts Here
</h2>
</motion.div>
</div>
<div className="grid md:grid-cols-3 gap-8">
{projeler.map((p, i) => (
<motion.div
key={i}
className="bg-[#FAF7F2] border border-[#E7E5E4] rounded-3xl p-6 hover:border-[#1E2E38] transition-colors"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: i * 0.15 }}
whileHover={{ y: -6 }}
>
<div className="w-10 h-10 rounded-xl bg-[#1E2E38]/5 flex items-center justify-center mb-6 text-xl">
{p.ikon}
</div>
<h3 className="font-display font-bold text-[#1E2E38] text-lg mb-1">{p.baslik}</h3>
<p className="text-gray-500 text-xs font-semibold">{p.aciklama}</p>
</motion.div>
))}
</div>
</div>
</section>
{/* ── YORUMLAR ── */}
<section id="yorumlar" className="py-24 bg-white px-6">
<div className="max-w-6xl mx-auto">
<div className="mb-16 text-center">
<span className="inline-block text-[11px] font-black uppercase tracking-widest text-[#1E2E38]/60 mb-4">
003 - Patient Stories
</span>
<h2 className="text-4xl font-display font-black text-[#1E2E38]">
Patient Experiences
</h2>
</div>
<div className="relative">
<AnimatePresence mode="wait">
<motion.div
key={activeYorum}
className="bg-[#FAF7F2] border border-[#1E2E38]/5 rounded-[36px] p-10 max-w-2xl mx-auto shadow-sm"
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
transition={{ duration: 0.4 }}>
<div className="flex gap-1 mb-6 justify-center">
{[...Array(yorumlar[activeYorum]?.puan)].map((_, i) => (
<span key={i} className="text-[#1E2E38] text-xl"></span>
))}
</div>
<p className="text-[#1E2E38]/80 text-lg leading-relaxed italic text-center mb-8 font-medium">
&ldquo;{yorumlar[activeYorum]?.yorum}&rdquo;
</p>
<div className="flex items-center gap-4 justify-center">
<div className="w-12 h-12 rounded-full flex items-center justify-center text-2xl bg-white shadow-sm border border-[#1E2E38]/5">
{yorumlar[activeYorum]?.emoji}
</div>
<div>
<p className="text-[#1E2E38] font-bold text-sm">{yorumlar[activeYorum]?.yazar}</p>
<p className="text-gray-400 text-xs">{yorumlar[activeYorum]?.tarih}</p>
</div>
</div>
</motion.div>
</AnimatePresence>
<div className="flex justify-center gap-2.5 mt-8">
{yorumlar.map((_, i) => (
<button key={i} onClick={() => setActiveYorum(i)}
className="w-2.5 h-2.5 rounded-full transition-all"
style={{ background: i === activeYorum ? "#1E2E38" : "rgba(30,46,56,0.15)",
transform: i === activeYorum ? "scale(1.3)" : "scale(1)" }} />
))}
</div>
</div>
</div>
</section>
{/* ── RANDEVU AL ── */}
<section id="randevu" className="py-24 bg-[#FAF7F2] px-6 border-t border-[#1E2E38]/5">
<div className="max-w-3xl mx-auto">
<div className="bg-white rounded-[40px] p-8 md:p-12 shadow-2xl border border-gray-100">
<div className="text-center mb-10">
<span className="inline-block text-[11px] font-black uppercase tracking-widest text-[#1E2E38]/60 mb-4">
004 - Online Appointment
</span>
<h2 className="text-3xl md:text-4xl font-display font-black text-[#1E2E38]">
Appointment Request
</h2>
<p className="text-gray-400 text-sm mt-2">
Hayalinizdeki sağlıklı gülüşe kavuşmak için formu doldurun, sizi arayalım.
</p>
</div>
<div className="grid grid-cols-2 gap-4">
{[
{ label: "Ad Soyad", placeholder: "Adınız Soyadınız", type: "text", full: false },
{ label: "Telefon", placeholder: "05xx xxx xx xx", type: "tel", full: false },
{ label: "E-posta", placeholder: "ornek@mail.com", type: "email", full: false },
{ label: "Hizmet Türü", placeholder: "", type: "select", full: false },
{ label: "Tercih Edilen Tarih", placeholder: "", type: "date", full: false },
{ label: "Şikayetiniz / Notunuz", placeholder: "Belirtmek istediğiniz detaylar...", type: "text", full: true },
].map((field, i) => (
<div key={i} className={field.full ? "col-span-2" : "col-span-1"}>
<label className="block text-[11px] font-bold text-[#1E2E38]/80 mb-1.5 uppercase tracking-wider">{field.label}</label>
{field.type === "select" ? (
<select className="w-full px-4 py-3 rounded-xl border border-gray-200 text-sm text-gray-700 focus:outline-none focus:ring-2 focus:ring-[#1E2E38] bg-gray-50/50 transition-all">
<option>Prevent Cavities & Disease</option>
<option>Teeth Sparkling Cleaning</option>
<option>Teeth Straightening</option>
<option>Dental Implant</option>
</select>
) : (
<input type={field.type} placeholder={field.placeholder}
className="w-full px-4 py-3 rounded-xl border border-gray-200 text-sm focus:outline-none focus:ring-2 focus:ring-[#1E2E38] bg-gray-50/50 transition-all" />
)}
</div>
))}
</div>
<motion.button
className="mt-8 w-full py-4 rounded-full text-[#FAF7F2] font-black text-sm bg-[#1E2E38] hover:bg-[#121C22]"
whileHover={{ scale: 1.02, boxShadow: "0 10px 30px rgba(30, 46, 56, 0.2)" }}
whileTap={{ scale: 0.98 }}
>
📅 Randevu Talep Et
</motion.button>
</div>
</div>
</section>
{/* ── FOOTER ── */}
<footer className="bg-[#121C22] border-t border-white/10 px-6 pt-16 pb-8">
<div className="max-w-6xl mx-auto">
<div className="flex flex-col md:flex-row justify-between items-center pt-8 gap-4 text-white/40">
<p className="text-xs">© 2026 {firma.adi}. Tüm hakları saklıdır.</p>
<p className="text-[10px]">Gizlilik Politikası · Çerez Ayarları</p>
</div>
</div>
</footer>
{/* ── BOOKING MODAL ── */}
<AnimatePresence>
{showBookingModal && (
<motion.div
className="fixed inset-0 z-50 flex items-center justify-center p-6 bg-black/60 backdrop-blur-sm"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
<motion.div
className="bg-white rounded-[36px] p-8 max-w-lg w-full relative shadow-2xl"
initial={{ scale: 0.9, y: 20 }}
animate={{ scale: 1, y: 0 }}
exit={{ scale: 0.9, y: 20 }}
>
<button
className="absolute top-6 right-6 w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center font-bold text-gray-500 hover:bg-gray-200 transition-colors"
onClick={() => setShowBookingModal(false)}
>
</button>
<h3 className="font-display font-black text-[#1E2E38] text-2xl mb-2">Hızlı İletişim</h3>
<p className="text-gray-400 text-xs mb-6">İletişim bilgilerinizi bırakın, en kısa sürede geri dönelim.</p>
<div className="space-y-4">
<div>
<label className="block text-[10px] font-bold text-gray-500 mb-1 uppercase">Ad Soyad</label>
<input type="text" className="w-full px-4 py-3 rounded-xl border bg-gray-50/50 text-sm focus:outline-none focus:ring-2 focus:ring-[#1E2E38]" placeholder="Adınız Soyadınız" />
</div>
<div>
<label className="block text-[10px] font-bold text-gray-500 mb-1 uppercase">Telefon Numarası</label>
<input type="tel" className="w-full px-4 py-3 rounded-xl border bg-gray-50/50 text-sm focus:outline-none focus:ring-2 focus:ring-[#1E2E38]" placeholder="05xx xxx xx xx" />
</div>
<motion.button
className="w-full py-4 rounded-full bg-[#1E2E38] text-[#FAF7F2] font-black text-sm hover:bg-[#121C22] transition-colors mt-2"
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
onClick={() => setShowBookingModal(false)}
>
Gönder
</motion.button>
</div>
</motion.div>
</motion.div>
)}
</AnimatePresence>
</div>
);
}
+423
View File
@@ -0,0 +1,423 @@
"use client";
import { motion, useScroll, useTransform, AnimatePresence } from "framer-motion";
import { useRef, useState } from "react";
import type { DemoData } from "@/data/demos";
import AnimatedCounter from "@/components/ui/AnimatedCounter";
const easeOutExpo = [0.16, 1, 0.3, 1] as [number, number, number, number];
const fadeUp = {
hidden: { opacity: 0, y: 40 },
show: { opacity: 1, y: 0, transition: { duration: 0.7, ease: easeOutExpo } },
};
const stagger = {
hidden: {},
show: { transition: { staggerChildren: 0.1 } },
};
export default function KlinikTemplate({ data }: { data: DemoData }) {
const { firma, istatistikler, hizmetler, doktorlar, yorumlar } = data;
const heroRef = useRef<HTMLDivElement>(null);
const { scrollYProgress } = useScroll({ target: heroRef, offset: ["start start", "end start"] });
const heroY = useTransform(scrollYProgress, [0, 1], ["0%", "30%"]);
const heroOpacity = useTransform(scrollYProgress, [0, 0.8], [1, 0]);
const [activeYorum, setActiveYorum] = useState(0);
const [menuOpen, setMenuOpen] = useState(false);
return (
<div className="bg-[#FAF9F6] text-[#1C1917] font-body">
{/* ── HEADER ── */}
<motion.header
className="fixed top-0 left-0 right-0 z-50 px-6 pt-5"
initial={{ y: -80 }}
animate={{ y: 0 }}
transition={{ duration: 0.6, ease: easeOutExpo }}
>
<div className="mx-auto max-w-6xl px-6 h-16 flex items-center justify-between bg-[#FAF9F6]/80 backdrop-blur-md border border-[#E7E5E4] rounded-full">
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-[#1C1917] flex items-center justify-center text-sm font-bold text-[#FAF9F6]">
{firma.logoEmoji}
</div>
<span className="font-display font-bold text-[15px] tracking-tight">{firma.adi}</span>
</div>
<nav className="hidden md:flex items-center gap-8">
{["Hizmetler", "Doktorlar", "Yorumlar", "İletişim"].map((item) => (
<a key={item} href={`#${item.toLowerCase()}`}
className="text-[12px] font-medium tracking-tight text-[#78716C] hover:text-[#1C1917] transition-colors duration-200">
{item}
</a>
))}
</nav>
<motion.a
href="#randevu"
className="hidden md:flex items-center gap-2 text-[12px] font-bold text-[#FAF9F6] bg-[#1C1917] px-5 py-2.5 rounded-full hover:bg-[#33302E] transition-colors"
whileTap={{ scale: 0.97 }}
>
Randevu Al
</motion.a>
<button className="md:hidden flex flex-col justify-center items-end gap-1 w-8 h-8 cursor-pointer" onClick={() => setMenuOpen(!menuOpen)}>
<span className={`h-0.5 bg-[#1C1917] transition-all duration-300 ${menuOpen ? "w-5 rotate-45 translate-y-1.5" : "w-5"}`} />
<span className={`h-0.5 bg-[#1C1917] transition-all duration-300 ${menuOpen ? "w-0 opacity-0" : "w-3"}`} />
<span className={`h-0.5 bg-[#1C1917] transition-all duration-300 ${menuOpen ? "w-5 -rotate-45 -translate-y-1.5" : "w-4"}`} />
</button>
</div>
{/* Mobile Dropdown */}
<AnimatePresence>
{menuOpen && (
<motion.div
className="md:hidden max-w-6xl mx-auto mt-2 bg-[#FAF9F6] border border-[#E7E5E4] rounded-2xl p-4 space-y-2"
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.3, ease: easeOutExpo }}
>
{["Hizmetler", "Doktorlar", "Yorumlar", "İletişim", "Randevu"].map(item => (
<a
key={item}
href={item === "Randevu" ? "#randevu" : `#${item.toLowerCase()}`}
className="block text-[14px] font-medium py-2 px-3 rounded-lg hover:bg-[#E7E5E4]/30 text-[#1C1917]"
onClick={() => setMenuOpen(false)}
>
{item}
</a>
))}
</motion.div>
)}
</AnimatePresence>
</motion.header>
{/* ── HERO ── */}
<section ref={heroRef} className="relative min-h-screen flex items-center overflow-hidden pt-24 pb-16 bg-[#FAF9F6]">
{/* Subtle grid pattern */}
<div className="absolute inset-0 pointer-events-none opacity-[0.03]"
style={{ backgroundImage: "radial-gradient(#1C1917 1px, transparent 1px)", backgroundSize: "32px 32px" }} />
<div className="relative z-10 max-w-6xl mx-auto px-6 w-full grid grid-cols-1 lg:grid-cols-12 gap-12 items-center">
{/* Hero Left */}
<motion.div className="lg:col-span-8" variants={stagger} initial="hidden" animate="show">
<motion.div variants={fadeUp}
className="inline-flex items-center gap-2 text-[11px] font-bold uppercase tracking-wider text-[#78716C] mb-8"
>
<span className="w-1.5 h-1.5 rounded-full bg-[#10B981]" />
{firma.sehir}&apos;in Modern Sağlık Üssü
</motion.div>
<motion.h1 variants={fadeUp}
className="font-display font-black text-[12vw] sm:text-[8vw] lg:text-[5vw] leading-[0.9] tracking-tight uppercase text-[#1C1917] mb-8">
Sağlığınız İçin<br />
<span className="text-transparent stroke-text" style={{ WebkitTextStroke: "1px #1C1917" }}>En Doğru</span> Adım.
</motion.h1>
<motion.p variants={fadeUp} className="text-[#57534E] text-base sm:text-lg leading-relaxed max-w-xl mb-10 font-light">
{firma.slogan}. Son teknoloji teşhis altyapımız ve alanında uzman hekim kadromuz ile her hastamıza kişiselleştirilmiş bir bakım süreci vadediyoruz.
</motion.p>
<motion.div variants={fadeUp} className="flex flex-wrap gap-4 mb-12">
<motion.a href="#randevu"
className="flex items-center justify-center px-8 py-4 rounded-full font-bold text-[13px] tracking-wide uppercase bg-[#1C1917] text-[#FAF9F6] cursor-pointer hover:bg-[#33302E] transition-all duration-200"
whileTap={{ scale: 0.97 }}>
📅 Randevu Oluştur
</motion.a>
<motion.a href="#hizmetler"
className="flex items-center justify-center px-8 py-4 rounded-full font-bold text-[13px] tracking-wide uppercase border border-[#E7E5E4] text-[#1C1917] hover:bg-[#E7E5E4]/20 transition-all cursor-pointer duration-200"
whileTap={{ scale: 0.97 }}>
Hizmetler
</motion.a>
</motion.div>
{/* Stats */}
<motion.div variants={fadeUp} className="grid grid-cols-2 sm:grid-cols-4 gap-6 pt-10 border-t border-[#E7E5E4]">
{istatistikler.map(s => {
const val = parseInt(s.deger.replace(/\D/g, "")) || 0;
const suf = s.deger.replace(/[0-9]/g, "");
return (
<div key={s.etiket}>
<div className="text-3xl font-display font-black text-[#1C1917]">
<AnimatedCounter target={val} suffix={suf} />
</div>
<div className="text-[#78716C] text-[10px] uppercase tracking-wider font-semibold mt-1">{s.etiket}</div>
</div>
);
})}
</motion.div>
</motion.div>
{/* Hero Right */}
<motion.div
className="lg:col-span-4 hidden lg:block"
initial={{ opacity: 0, x: 30 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.8, delay: 0.3, ease: easeOutExpo }}
style={{ y: heroY }}
>
<div className="bg-[#FAF9F6] border border-[#E7E5E4] rounded-3xl p-6 shadow-sm">
<div className="flex items-center justify-between border-b border-[#E7E5E4] pb-4 mb-4">
<span className="font-display font-bold text-[12px] uppercase tracking-wider text-[#78716C]">Günlük Randevu Akışı</span>
<span className="w-1.5 h-1.5 rounded-full bg-[#10B981] animate-pulse" />
</div>
<div className="space-y-3">
{[
{ saat: "09:30", tip: "Genel Muayene", dolu: true },
{ saat: "11:00", tip: "Check-Up Kontrol", dolu: false },
{ saat: "13:30", tip: "Kardiyoloji Muayenesi", dolu: true },
{ saat: "15:00", tip: "Göz Polikliniği", dolu: false },
].map((r, i) => (
<div key={i} className="flex items-center justify-between p-3 rounded-2xl bg-[#FAF9F6] border border-[#E7E5E4]/60">
<div className="flex items-center gap-3">
<span className={`w-2 h-2 rounded-full ${r.dolu ? "bg-red-400" : "bg-green-400"}`} />
<div>
<p className="text-[#1C1917] text-[12px] font-bold">{r.saat}</p>
<p className="text-[#78716C] text-[10px]">{r.tip}</p>
</div>
</div>
<span className={`text-[10px] font-bold px-2 py-0.5 rounded-full ${r.dolu ? "bg-red-50 text-red-500" : "bg-green-50 text-green-500"}`}>
{r.dolu ? "Dolu" : "Müsait"}
</span>
</div>
))}
</div>
</div>
</motion.div>
</div>
</section>
{/* ── HİZMETLER ── */}
<section id="hizmetler" className="py-24 px-6 border-t border-[#E7E5E4] bg-[#FAF9F6]">
<div className="max-w-6xl mx-auto">
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6 border-b border-[#E7E5E4] pb-12 mb-16">
<div className="lg:col-span-5">
<span className="inline-block text-[11px] font-bold uppercase tracking-widest px-3 py-1 bg-[#FAF9F6] border border-[#E7E5E4] rounded-full text-[#78716C] mb-4">
Tıbbi Birimlerimiz
</span>
<h2 className="font-display font-black text-4xl sm:text-5xl uppercase leading-tight tracking-tight text-[#1C1917]">
Kapsamlı Tedavi Çözümleri
</h2>
</div>
<div className="lg:col-span-7 flex items-end">
<p className="text-[#57534E] text-base leading-relaxed font-light lg:pl-8 border-l border-transparent lg:border-[#E7E5E4]">
Her branşta yüksek teknolojik imkanlarla entegre edilmiş tanı ünitelerimiz ile kusursuz bir klinik deneyim sunuyoruz.
</p>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{hizmetler.map((h, i) => (
<motion.div key={i}
className="group p-8 rounded-3xl border border-[#E7E5E4] bg-[#FAF9F6] hover:border-[#1C1917] transition-all duration-300 flex flex-col justify-between min-h-[220px]"
whileHover={{ y: -4 }}
initial="hidden"
whileInView="show"
viewport={{ once: true }}
variants={fadeUp}>
<div>
<div className="w-10 h-10 rounded-xl bg-[#1C1917]/5 flex items-center justify-center mb-6 group-hover:bg-[#1C1917] group-hover:text-[#FAF9F6] transition-colors duration-300">
<span className="text-xl">🩺</span>
</div>
<h3 className="font-display font-black text-xl uppercase text-[#1C1917] mb-2">{h.baslik}</h3>
<p className="text-[#57534E] text-[13px] leading-relaxed font-light">{h.aciklama}</p>
</div>
</motion.div>
))}
</div>
</div>
</section>
{/* ── DOKTORLAR ── */}
{doktorlar && (
<section id="doktorlar" className="py-24 px-6 border-t border-[#E7E5E4] bg-[#FAF9F6]">
<div className="max-w-6xl mx-auto">
<div className="mb-16">
<span className="inline-block text-[11px] font-bold uppercase tracking-widest px-3 py-1 bg-[#FAF9F6] border border-[#E7E5E4] rounded-full text-[#78716C] mb-4">
Hekim Kadromuz
</span>
<h2 className="font-display font-black text-4xl sm:text-5xl uppercase tracking-tight text-[#1C1917]">
Alanında Öncü Akademik Ekip
</h2>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
{doktorlar.map((d, i) => (
<motion.div key={i}
className="bg-[#FAF9F6] border border-[#E7E5E4] rounded-3xl overflow-hidden hover:border-[#1C1917] transition-all duration-300 flex flex-col justify-between"
whileHover={{ y: -6 }}
initial="hidden"
whileInView="show"
viewport={{ once: true }}
variants={fadeUp}>
<div className="h-44 bg-[#FAF9F6] border-b border-[#E7E5E4] flex items-center justify-center text-5xl relative">
<span className="z-10">{d.emoji}</span>
</div>
<div className="p-6">
<h3 className="font-display font-black text-[15px] uppercase text-[#1C1917]">{d.ad}</h3>
<p className="text-[12px] font-bold uppercase tracking-wider text-[#78716C] mt-0.5 mb-3">{d.uzmanlik}</p>
<div className="flex items-center justify-between text-[11px] text-[#78716C] pt-3 border-t border-[#E7E5E4]/60">
<span> {d.puan}</span>
<span>🏥 {d.yil} Yıl</span>
<span>👥 {d.hasta}+ Hasta</span>
</div>
</div>
</motion.div>
))}
</div>
</div>
</section>
)}
{/* ── RANDEVU ── */}
<section id="randevu" className="py-24 px-6 border-t border-[#E7E5E4] bg-[#FAF9F6]">
<div className="max-w-6xl mx-auto">
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12 items-start">
{/* Left */}
<div className="lg:col-span-5">
<span className="inline-block text-[11px] font-bold uppercase tracking-widest px-3 py-1 bg-[#FAF9F6] border border-[#E7E5E4] rounded-full text-[#78716C] mb-4">
Hızlı Destek Hattı
</span>
<h2 className="font-display font-black text-4xl sm:text-5xl uppercase tracking-tight text-[#1C1917] leading-tight mb-8">
İletişime Geçin
</h2>
<p className="text-[#57534E] text-base font-light mb-10">
Form üzerinden randevu talebi oluşturun. Tıbbi sekreterliğimiz detayları onaylamak üzere sizi en kısa sürede arayacaktır.
</p>
<div className="space-y-4">
{[
{ ikon: "📞", baslik: "Çağrı Merkezi", val: firma.telefon },
{ ikon: "📍", baslik: "Poliklinik Adresi", val: firma.adres },
{ ikon: "✉️", baslik: "Resmi Yazışmalar", val: firma.email },
].map((item) => (
<div key={item.baslik} className="flex gap-4 bg-[#FAF9F6] border border-[#E7E5E4] rounded-2xl p-4">
<span className="text-xl">{item.ikon}</span>
<div>
<p className="text-[#78716C] text-[10px] font-bold uppercase tracking-wider">{item.baslik}</p>
<p className="text-[#1C1917] text-[13px] font-semibold mt-0.5">{item.val}</p>
</div>
</div>
))}
</div>
</div>
{/* Right Form */}
<div className="lg:col-span-7 bg-[#FAF9F6] border border-[#E7E5E4] rounded-3xl p-8 shadow-sm">
<h3 className="font-display font-black text-xl uppercase text-[#1C1917] mb-6">Online Randevu Formu</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
{[
{ label: "Hasta Adı Soyadı", placeholder: "Ad Soyad", type: "text" },
{ label: "Telefon Numarası", placeholder: "05xx xxx xx xx", type: "tel" },
{ label: "E-Posta Adresi", placeholder: "e-posta@adresiniz.com", type: "email" },
{ label: "Birim / Poliklinik", type: "select" },
{ label: "Tercih Edilen Tarih", type: "date" },
{ label: "Şikayet / Not", placeholder: "Tıbbi geçmişiniz veya eklemek istediğiniz notlar...", type: "textarea", full: true }
].map((field, i) => (
<div key={i} className={field.full ? "sm:col-span-2 flex flex-col" : "flex flex-col"}>
<label className="text-[11px] font-bold uppercase tracking-wider text-[#78716C] mb-2">{field.label}</label>
{field.type === "select" ? (
<select className="w-full px-0 py-3 bg-transparent border-b border-[#E7E5E4] text-[#1C1917] text-sm focus:outline-none focus:border-[#1C1917] transition-colors rounded-none appearance-none cursor-pointer">
<option>Dahiliye</option>
<option>Kardiyoloji</option>
<option>Göz Sağlığı</option>
<option>Diş Hekimliği</option>
</select>
) : field.type === "textarea" ? (
<textarea rows={3} placeholder={field.placeholder} className="w-full px-0 py-3 bg-transparent border-b border-[#E7E5E4] text-[#1C1917] placeholder-[#78716C]/40 text-sm focus:outline-none focus:border-[#1C1917] transition-colors resize-none rounded-none" />
) : (
<input type={field.type} placeholder={field.placeholder} className="w-full px-0 py-3 bg-transparent border-b border-[#E7E5E4] text-[#1C1917] placeholder-[#78716C]/40 text-sm focus:outline-none focus:border-[#1C1917] transition-colors rounded-none" />
)}
</div>
))}
</div>
<motion.button
className="mt-8 w-full py-4 rounded-full font-bold text-[13px] tracking-wide uppercase bg-[#1C1917] text-[#FAF9F6] hover:bg-[#33302E] transition-colors cursor-pointer"
whileTap={{ scale: 0.98 }}>
Randevu Talebi Gönder
</motion.button>
</div>
</div>
</div>
</section>
{/* ── YORUMLAR ── */}
<section id="yorumlar" className="py-24 px-6 border-t border-[#E7E5E4] bg-[#FAF9F6]">
<div className="max-w-3xl mx-auto">
<div className="mb-16 text-center">
<span className="inline-block text-[11px] font-bold uppercase tracking-widest px-3 py-1 bg-[#FAF9F6] border border-[#E7E5E4] rounded-full text-[#78716C] mb-4">
Hasta Görüşleri
</span>
<h2 className="font-display font-black text-4xl sm:text-5xl uppercase tracking-tight text-[#1C1917]">
Hasta Deneyimleri
</h2>
</div>
<div className="relative border border-[#E7E5E4] rounded-3xl p-8 bg-[#FAF9F6]">
<AnimatePresence mode="wait">
<motion.div
key={activeYorum}
className="min-h-[160px] flex flex-col justify-between"
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.4 }}>
<div>
<div className="flex gap-1 mb-4">
{[...Array(yorumlar[activeYorum].puan)].map((_, i) => (
<span key={i} className="text-yellow-500 text-lg"></span>
))}
</div>
<p className="text-[#57534E] text-base leading-relaxed italic font-light mb-6">
&ldquo;{yorumlar[activeYorum].yorum}&rdquo;
</p>
</div>
<div className="flex items-center gap-3 pt-4 border-t border-[#E7E5E4]/60">
<span className="text-2xl">{yorumlar[activeYorum].emoji}</span>
<div>
<p className="text-[#1C1917] font-bold text-sm uppercase tracking-tight">{yorumlar[activeYorum].yazar}</p>
<p className="text-[#78716C] text-[11px]">{yorumlar[activeYorum].tarih}</p>
</div>
</div>
</motion.div>
</AnimatePresence>
<div className="flex justify-center gap-2 mt-8">
{yorumlar.map((_, i) => (
<button key={i} onClick={() => setActiveYorum(i)}
className="w-2 h-2 rounded-full cursor-pointer transition-all"
style={{ background: i === activeYorum ? "#1C1917" : "#E7E5E4",
transform: i === activeYorum ? "scale(1.2)" : "scale(1)" }} />
))}
</div>
</div>
</div>
</section>
{/* ── FOOTER ── */}
<footer className="border-t border-[#E7E5E4] bg-[#FAF9F6] px-6 pt-16 pb-8">
<div className="max-w-6xl mx-auto flex flex-col sm:flex-row justify-between items-center gap-4 text-[12px] text-[#78716C]">
<p>© 2026 {firma.adi}. Tüm hakları saklıdır.</p>
<div className="flex gap-6">
<a href="#" className="hover:text-[#1C1917] font-light">Gizlilik Bildirgesi</a>
<a href="#" className="hover:text-[#1C1917] font-light">Çerez Ayarları</a>
</div>
</div>
</footer>
<style jsx global>{`
.stroke-text {
font-weight: 900;
color: transparent;
}
`}</style>
</div>
);
}
+335
View File
@@ -0,0 +1,335 @@
"use client";
import { motion, useScroll, useTransform } from "framer-motion";
import { useRef } from "react";
import type { DemoData } from "@/data/demos";
import AnimatedCounter from "@/components/ui/AnimatedCounter";
const easeOutExpo = [0.16, 1, 0.3, 1] as [number, number, number, number];
const fadeUp = {
hidden: { opacity: 0, y: 40 },
show: { opacity: 1, y: 0, transition: { duration: 0.7, ease: easeOutExpo } },
};
const stagger = { hidden: {}, show: { transition: { staggerChildren: 0.1 } } };
export default function KurumsalTemplate({ data }: { data: DemoData }) {
const { firma, istatistikler, hizmetler, yorumlar, projeler = [], ekip = [] } = data;
const heroRef = useRef<HTMLDivElement>(null);
const { scrollYProgress } = useScroll({ target: heroRef, offset: ["start start", "end start"] });
const heroY = useTransform(scrollYProgress, [0, 1], ["0%", "20%"]);
return (
<div className="bg-[#FAF9F6] text-[#1C1917] font-body">
{/* ── HEADER ── */}
<motion.header
className="fixed top-0 left-0 right-0 z-50 px-6 pt-5"
initial={{ y: -80 }}
animate={{ y: 0 }}
transition={{ duration: 0.6, ease: easeOutExpo }}>
<div className="mx-auto max-w-6xl px-6 h-16 flex items-center justify-between bg-[#FAF9F6]/80 backdrop-blur-md border border-[#E7E5E4] rounded-full">
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-[#1C1917] flex items-center justify-center text-sm font-bold text-[#FAF9F6]">
{firma.logoEmoji}
</div>
<span className="font-display font-bold text-[15px] tracking-tight">{firma.adi}</span>
</div>
<nav className="hidden md:flex items-center gap-8">
{["Hizmetler", "Projeler", "Ekip", "İletişim"].map(item => (
<a key={item} href={`#${item.toLowerCase()}`}
className="text-[12px] font-medium tracking-tight text-[#78716C] hover:text-[#1C1917] transition-colors">
{item}
</a>
))}
</nav>
<motion.a href="#iletisim"
className="hidden md:flex items-center gap-2 text-[12px] font-bold text-[#FAF9F6] bg-[#1C1917] px-5 py-2.5 rounded-full hover:bg-[#33302E] transition-colors"
whileTap={{ scale: 0.97 }}>
Teklif Al
</motion.a>
</div>
</motion.header>
{/* ── HERO ── */}
<section ref={heroRef} className="relative min-h-screen flex items-center overflow-hidden bg-[#FAF9F6] pt-24">
{/* Subtle grid pattern */}
<div className="absolute inset-0 pointer-events-none opacity-[0.03]"
style={{ backgroundImage: "radial-gradient(#1C1917 1px, transparent 1px)", backgroundSize: "32px 32px" }} />
<div className="relative z-10 max-w-6xl mx-auto px-6 w-full grid grid-cols-1 lg:grid-cols-12 gap-12 items-center">
<motion.div className="lg:col-span-8" variants={stagger} initial="hidden" animate="show">
<motion.div variants={fadeUp}
className="inline-flex items-center gap-2 text-[11px] font-bold uppercase tracking-wider text-[#78716C] mb-8"
>
<span className="w-1.5 h-1.5 rounded-full bg-[#10B981]" />
{firma.sehir} · {istatistikler[0]?.deger} Lojistik Hizmeti
</motion.div>
<motion.h1 variants={fadeUp}
className="font-display font-black text-[12vw] sm:text-[8vw] lg:text-[5vw] leading-[0.9] tracking-tight uppercase text-[#1C1917] mb-8">
Lojistikte<br />
<span className="text-transparent stroke-text" style={{ WebkitTextStroke: "1px #1C1917" }}>Yeni Nesil</span> Ağı.
</motion.h1>
<motion.p variants={fadeUp} className="text-[#57534E] text-base sm:text-lg leading-relaxed max-w-xl mb-10 font-light">
{firma.slogan}. Tedarik zincirinizin uçtan uca akışını optimize etmek için geliştirilmiş son derece güvenli ve anlık takip edilebilen operasyon sistemleri.
</motion.p>
<motion.div variants={fadeUp} className="flex flex-wrap gap-4 mb-12">
<motion.a href="#iletisim"
className="flex items-center justify-center px-8 py-4 rounded-full font-bold text-[13px] tracking-wide uppercase bg-[#1C1917] text-[#FAF9F6] cursor-pointer hover:bg-[#33302E] transition-all duration-200"
whileTap={{ scale: 0.97 }}>
Teklif Al
</motion.a>
<motion.a href="#projeler"
className="flex items-center justify-center px-8 py-4 rounded-full font-bold text-[13px] tracking-wide uppercase border border-[#E7E5E4] text-[#1C1917] hover:bg-[#E7E5E4]/20 transition-all cursor-pointer duration-200"
whileTap={{ scale: 0.97 }}>
Referanslar
</motion.a>
</motion.div>
{/* Stats row */}
<motion.div variants={fadeUp}
className="grid grid-cols-2 sm:grid-cols-4 gap-6 pt-10 border-t border-[#E7E5E4]">
{istatistikler.map((s, i) => (
<div key={i}>
<div className="text-3xl font-display font-black text-[#1C1917]">
<AnimatedCounter target={parseInt(s.deger.replace(/\D/g, "")) || 0}
suffix={s.deger.replace(/[0-9]/g, "")} />
</div>
<div className="text-[#78716C] text-[10px] uppercase tracking-wider font-semibold mt-1">{s.etiket}</div>
</div>
))}
</motion.div>
</motion.div>
{/* Bento grid right side */}
<motion.div
className="lg:col-span-4 hidden lg:grid grid-cols-2 gap-4"
initial={{ opacity: 0, x: 60 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.9, delay: 0.3 }}
style={{ y: heroY }}
>
{hizmetler.slice(0, 4).map((h, i) => (
<div key={i} className="bg-[#FAF9F6] border border-[#E7E5E4] rounded-3xl p-6 shadow-sm">
<div className="w-10 h-10 rounded-xl bg-[#1C1917]/5 flex items-center justify-center mb-4 text-xl">
{h.ikon}
</div>
<h3 className="font-display font-black text-[12px] uppercase text-[#1C1917] mb-1">{h.baslik}</h3>
<p className="text-[#78716C] text-[10px] leading-relaxed font-light">{h.aciklama}</p>
</div>
))}
</motion.div>
</div>
</section>
{/* ── HİZMETLER TAM ── */}
<section id="hizmetler" className="py-24 px-6 border-t border-[#E7E5E4] bg-[#FAF9F6]">
<div className="max-w-6xl mx-auto">
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6 border-b border-[#E7E5E4] pb-12 mb-16">
<div className="lg:col-span-5">
<span className="inline-block text-[11px] font-bold uppercase tracking-widest px-3 py-1 bg-[#FAF9F6] border border-[#E7E5E4] rounded-full text-[#78716C] mb-4">
Uçtan Uca Çözümler
</span>
<h2 className="font-display font-black text-4xl sm:text-5xl uppercase leading-tight tracking-tight text-[#1C1917]">
Kapsamlı Lojistik Paketi
</h2>
</div>
<div className="lg:col-span-7 flex items-end">
<p className="text-[#57534E] text-base leading-relaxed font-light lg:pl-8 border-l border-transparent lg:border-[#E7E5E4]">
Operasyonel mükemmeliyetçiliği temel alan depolama, yurt içi dağıtım ve anlık takip sistemlerimizle tedarik zincirinize tam entegrasyon sunuyoruz.
</p>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{hizmetler.map((h, i) => (
<motion.div key={i}
className="bg-[#FAF9F6] border border-[#E7E5E4] rounded-3xl p-8 hover:border-[#1C1917] transition-all duration-300 flex flex-col justify-between min-h-[220px]"
whileHover={{ y: -4 }}
initial="hidden"
whileInView="show"
viewport={{ once: true }}
variants={fadeUp}>
<div>
<div className="w-10 h-10 rounded-xl bg-[#1C1917]/5 flex items-center justify-center mb-6 text-xl">
{h.ikon}
</div>
<h3 className="font-display font-black text-xl uppercase text-[#1C1917] mb-2">{h.baslik}</h3>
<p className="text-[#57534E] text-[13px] leading-relaxed font-light">{h.aciklama}</p>
</div>
</motion.div>
))}
</div>
</div>
</section>
{/* ── REFERANSLAR ── */}
<section id="projeler" className="py-24 px-6 border-t border-[#E7E5E4] bg-[#FAF9F6]">
<div className="max-w-6xl mx-auto">
<div className="mb-16">
<span className="inline-block text-[11px] font-bold uppercase tracking-widest px-3 py-1 bg-[#FAF9F6] border border-[#E7E5E4] rounded-full text-[#78716C] mb-4">
Güçlü Referanslar
</span>
<h2 className="font-display font-black text-4xl sm:text-5xl uppercase tracking-tight text-[#1C1917]">
Birlikte Yol Aldıklarımız
</h2>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{projeler.map((p, i) => (
<motion.div key={i}
className="bg-[#FAF9F6] border border-[#E7E5E4] rounded-3xl p-7 flex flex-col justify-between hover:border-[#1C1917] transition-all duration-300 relative overflow-hidden"
whileHover={{ y: -4 }}
initial="hidden"
whileInView="show"
viewport={{ once: true }}
variants={fadeUp}>
<div className="flex items-start gap-5">
<div className="w-14 h-14 rounded-2xl flex items-center justify-center text-2xl shrink-0"
style={{ background: `${p.renk}10` }}>
{p.ikon}
</div>
<div>
<div className="flex items-center gap-3 mb-2">
<h3 className="font-display font-black text-[16px] uppercase text-[#1C1917]">{p.baslik}</h3>
<span className="text-[10px] font-bold px-2 py-0.5 rounded-full"
style={{ background: `${p.renk}10`, color: p.renk }}>
{p.sektor}
</span>
</div>
<p className="text-[#57534E] text-[13px] leading-relaxed font-light">{p.aciklama}</p>
</div>
</div>
</motion.div>
))}
</div>
</div>
</section>
{/* ── EKİP ── */}
{ekip.length > 0 && (
<section id="ekip" className="py-24 px-6 border-t border-[#E7E5E4] bg-[#FAF9F6]">
<div className="max-w-6xl mx-auto">
<div className="mb-16">
<span className="inline-block text-[11px] font-bold uppercase tracking-widest px-3 py-1 bg-[#FAF9F6] border border-[#E7E5E4] rounded-full text-[#78716C] mb-4">
Operasyon Liderleri
</span>
<h2 className="font-display font-black text-4xl sm:text-5xl uppercase tracking-tight text-[#1C1917]">
Yönetim Ekibimiz
</h2>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
{ekip.map((k, i) => (
<motion.div key={i}
className="bg-[#FAF9F6] border border-[#E7E5E4] rounded-3xl overflow-hidden hover:border-[#1C1917] transition-all duration-300 flex flex-col justify-between"
whileHover={{ y: -6 }}
initial="hidden"
whileInView="show"
viewport={{ once: true }}
variants={fadeUp}>
<div className="h-40 bg-[#FAF9F6] border-b border-[#E7E5E4] flex items-center justify-center text-5xl">
<span>{k.emoji}</span>
</div>
<div className="p-6">
<h3 className="font-display font-black text-[15px] uppercase text-[#1C1917]">{k.ad}</h3>
<p className="text-[12px] font-bold uppercase tracking-wider text-[#78716C] mt-0.5">{k.rol}</p>
</div>
</motion.div>
))}
</div>
</div>
</section>
)}
{/* ── YORUMLAR ── */}
<section id="yorumlar" className="py-24 px-6 border-t border-[#E7E5E4] bg-[#FAF9F6]">
<div className="max-w-6xl mx-auto">
<div className="mb-16">
<span className="inline-block text-[11px] font-bold uppercase tracking-widest px-3 py-1 bg-[#FAF9F6] border border-[#E7E5E4] rounded-full text-[#78716C] mb-4">
Müşteri Deneyimleri
</span>
<h2 className="font-display font-black text-4xl sm:text-5xl uppercase tracking-tight text-[#1C1917]">
Ortaklarımız Ne Söylüyor?
</h2>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{yorumlar.map((y, i) => (
<motion.div key={i}
className="bg-[#FAF9F6] border border-[#E7E5E4] rounded-3xl p-7 hover:border-[#1C1917] transition-all duration-300 flex flex-col justify-between"
whileHover={{ y: -4 }}
initial="hidden"
whileInView="show"
viewport={{ once: true }}
variants={fadeUp}>
<div>
<div className="flex gap-1 mb-4">
{[...Array(y.puan)].map((_, j) => (
<span key={j} className="text-[#10B981]"></span>
))}
</div>
<p className="text-[#57534E] text-[13px] leading-relaxed italic mb-6 font-light">&ldquo;{y.yorum}&rdquo;</p>
</div>
<div className="flex items-center gap-3 pt-4 border-t border-[#E7E5E4]/60">
<span className="text-xl">{y.emoji}</span>
<div>
<p className="text-[#1C1917] font-bold text-xs uppercase tracking-tight">{y.yazar}</p>
<p className="text-gray-400 text-[10px] mt-0.5">{y.tarih}</p>
</div>
</div>
</motion.div>
))}
</div>
</div>
</section>
{/* ── İLETİŞİM ── */}
<section id="iletisim" className="py-24 px-6 border-t border-[#E7E5E4] bg-[#FAF9F6]">
<div className="max-w-4xl mx-auto text-center">
<span className="inline-block text-[11px] font-bold uppercase tracking-widest px-3 py-1 bg-[#FAF9F6] border border-[#E7E5E4] rounded-full text-[#78716C] mb-4">
Operational Blueprint
</span>
<h2 className="font-display font-black text-4xl sm:text-5xl uppercase tracking-tight text-[#1C1917] mb-6">
Birlikte Değer Katalım
</h2>
<p className="text-[#57534E] text-lg font-light mb-10 max-w-xl mx-auto">
Hacminiz ve operasyon sıklığınız ne olursa olsun, lojistik süreçlerinizi en güvenli hatlarla optimize etmek üzere teklif isteyin.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<motion.a href={`tel:${firma.telefon}`}
className="flex items-center justify-center gap-2 px-8 py-4 rounded-full bg-[#1C1917] text-[#FAF9F6] font-bold text-[13px] tracking-wide uppercase hover:bg-[#33302E] transition-colors"
whileHover={{ scale: 1.04 }} whileTap={{ scale: 0.97 }}>
📞 {firma.telefon}
</motion.a>
<motion.a href={`mailto:${firma.email}`}
className="flex items-center justify-center gap-2 px-8 py-4 rounded-full border border-[#E7E5E4] text-[#1C1917] font-bold text-[13px] tracking-wide uppercase hover:bg-[#E7E5E4]/20 transition-all"
whileHover={{ scale: 1.04 }} whileTap={{ scale: 0.97 }}>
{firma.email}
</motion.a>
</div>
</div>
</section>
{/* ── FOOTER ── */}
<footer className="border-t border-[#E7E5E4] bg-[#FAF9F6] px-6 pt-16 pb-8">
<div className="max-w-6xl mx-auto flex flex-col sm:flex-row justify-between items-center gap-4 text-[12px] text-[#78716C]">
<p>© 2026 {firma.adi}. Tüm hakları saklıdır.</p>
<p className="hover:text-[#1C1917] transition-colors font-light">Gizlilik Politikası</p>
</div>
</footer>
<style jsx global>{`
.stroke-text {
font-weight: 900;
color: transparent;
}
`}</style>
</div>
);
}
+508
View File
@@ -0,0 +1,508 @@
"use client";
import { motion, useScroll, useTransform, AnimatePresence } from "framer-motion";
import { useRef, useState } from "react";
import type { DemoData } from "@/data/demos";
import AnimatedCounter from "@/components/ui/AnimatedCounter";
const easeOutExpo = [0.16, 1, 0.3, 1] as [number, number, number, number];
const fadeUp = {
hidden: { opacity: 0, y: 40 },
show: { opacity: 1, y: 0, transition: { duration: 0.7, ease: easeOutExpo } },
};
const stagger = {
hidden: {},
show: { transition: { staggerChildren: 0.1 } },
};
export default function RestoranTemplate({ data }: { data: DemoData }) {
const { firma, istatistikler, hizmetler, menu = [], yorumlar = [] } = data;
const heroRef = useRef<HTMLDivElement>(null);
const { scrollYProgress } = useScroll({ target: heroRef, offset: ["start start", "end start"] });
const heroY = useTransform(scrollYProgress, [0, 1], ["0%", "20%"]);
const heroOpacity = useTransform(scrollYProgress, [0, 0.8], [1, 0]);
const [aktifKategori, setAktifKategori] = useState(0);
const [showBookingModal, setShowBookingModal] = useState(false);
// SVG Render Helper for clean iconography (Replaces all emojis)
const getIconSvg = (name: string) => {
switch (name) {
case "alacarte":
return (
<svg className="w-6 h-6 stroke-[#C5A880]" viewBox="0 0 24 24" fill="none" strokeWidth="1.5">
<path strokeLinecap="round" strokeLinejoin="round" d="M12 6.042A8.967 8.967 0 0 0 6 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 0 1 6 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 0 1 6-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0 0 18 18a8.967 8.967 0 0 0-6 2.292m0-14.25v14.25" />
</svg>
);
case "special":
return (
<svg className="w-6 h-6 stroke-[#C5A880]" viewBox="0 0 24 24" fill="none" strokeWidth="1.5">
<path strokeLinecap="round" strokeLinejoin="round" 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>
);
case "catering":
return (
<svg className="w-6 h-6 stroke-[#C5A880]" viewBox="0 0 24 24" fill="none" strokeWidth="1.5">
<path strokeLinecap="round" strokeLinejoin="round" d="M15.75 10.5V6a3.75 3.75 0 1 0-7.5 0v4.5m11.356-1.993 1.263 12c.07.665-.45 1.243-1.119 1.243H4.25a1.125 1.125 0 0 1-1.12-1.243l1.264-12A1.125 1.125 0 0 1 5.513 7.5h12.974c.576 0 1.059.435 1.119 1.007ZM8.625 10.5a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm7.5 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z" />
</svg>
);
case "delivery":
return (
<svg className="w-6 h-6 stroke-[#C5A880]" viewBox="0 0 24 24" fill="none" strokeWidth="1.5">
<path strokeLinecap="round" strokeLinejoin="round" d="M8.25 18.75a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0ZM19.5 18.75a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0Z" />
<path strokeLinecap="round" strokeLinejoin="round" d="M2.25 3h1.386c.51 0 .955.343 1.087.835l.383 1.437M7.5 14.25a3 3 0 0 0-3 3h15.75m-12.75-3h11.218c1.121-2.3 2.1-4.684 2.924-7.138a60.114 60.114 0 0 0-16.536-1.84" />
</svg>
);
default:
return (
<svg className="w-6 h-6 stroke-[#C5A880]" viewBox="0 0 24 24" fill="none" strokeWidth="1.5">
<path strokeLinecap="round" d="M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21" />
</svg>
);
}
};
return (
<div className="bg-[#090A0C] text-white font-body">
{/* ── FLOATING NAVIGATION HEADER ── */}
<motion.header
className="fixed top-4 left-4 right-4 z-50 px-4"
initial={{ y: -80, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ duration: 0.7, ease: easeOutExpo }}
>
<div className="mx-auto max-w-6xl h-20 flex items-center justify-between px-8 bg-[#090A0C]/80 backdrop-blur-xl border border-[#C5A880]/20 rounded-2xl shadow-2xl">
<a href="#" className="flex items-center gap-3 group">
<span className="font-display text-2xl font-bold tracking-widest text-white group-hover:text-[#C5A880] transition-colors uppercase">
{firma.adi}
</span>
</a>
<nav className="hidden lg:flex items-center gap-10">
{[
{ label: "Our Heritage", href: "#heritage" },
{ label: "Special Meal", href: "#special-meal" },
{ label: "Chalkboard Bakery", href: "#bakery" },
{ label: "Hizmetlerimiz", href: "#services" },
{ label: "Rezervasyon", href: "#randevu" }
].map(item => (
<a
key={item.label}
href={item.href}
className="text-[11px] font-sans-clean font-bold tracking-[2px] uppercase text-white/60 hover:text-white transition-colors cursor-pointer"
>
{item.label}
</a>
))}
</nav>
<div className="flex items-center gap-6">
<motion.button
onClick={() => setShowBookingModal(true)}
className="text-[11px] font-sans-clean font-black tracking-[2px] uppercase text-[#C5A880] border border-[#C5A880] hover:bg-[#C5A880] hover:text-[#090A0C] px-6 py-3 rounded-xl transition-all cursor-pointer"
whileHover={{ scale: 1.03 }}
whileTap={{ scale: 0.98 }}
>
Enquiry
</motion.button>
</div>
</div>
</motion.header>
{/* ── HERO SECTION ── */}
<section ref={heroRef} className="relative min-h-screen flex items-center justify-center overflow-hidden bg-[#090A0C]">
<motion.div
className="absolute inset-0 pointer-events-none"
style={{ y: heroY, opacity: heroOpacity }}
>
<div className="absolute inset-0 bg-gradient-to-b from-black/80 via-black/60 to-[#090A0C] z-10" />
</motion.div>
<div className="relative z-20 max-w-5xl mx-auto px-6 text-center pt-24">
<motion.div
variants={stagger}
initial="hidden"
animate="show"
className="flex flex-col items-center"
>
<motion.span
variants={fadeUp}
className="text-[#C5A880] italic text-lg lg:text-xl tracking-wider mb-6 block font-display"
>
welcome to our delicious corner
</motion.span>
<motion.h1
variants={fadeUp}
className="font-display text-5xl md:text-7xl lg:text-8xl font-black text-white leading-[1.05] tracking-widest uppercase mb-8"
>
Best Famous
<br />
Dishes
</motion.h1>
<motion.p
variants={fadeUp}
className="text-white/60 font-sans-clean font-medium text-sm lg:text-base leading-relaxed max-w-lg mb-12"
>
A journey of raw ingredients transformed by fire, smoke, and heritage. Exquisite tastes curated for refined palates.
</motion.p>
<motion.div variants={fadeUp}>
<motion.a
href="#special-meal"
className="inline-flex items-center gap-3 text-[11px] font-sans-clean font-bold tracking-[3px] uppercase border-b-2 border-[#C5A880] text-white hover:text-[#C5A880] pb-2 transition-colors cursor-pointer"
whileHover={{ y: -3 }}
>
Learn More
</motion.a>
</motion.div>
</motion.div>
</div>
</section>
{/* ── SECTION 2: HERITAGE ── */}
<section id="heritage" className="py-32 bg-[#090A0C] border-t border-[#C5A880]/15 relative z-10 px-6">
<div className="max-w-6xl mx-auto">
<div className="text-center mb-24">
<span className="text-[#C5A880] font-display italic text-base tracking-wider block mb-3">Special moments</span>
<h2 className="font-display text-4xl lg:text-5xl font-black tracking-widest text-white uppercase">
About Us
</h2>
</div>
<div className="grid lg:grid-cols-3 gap-8 items-stretch">
<div className="bg-[#13151A] rounded-2xl p-10 border border-[#C5A880]/10 flex flex-col items-center justify-center text-center shadow-2xl relative min-h-[300px]">
<span className="text-[#C5A880] text-xs tracking-wider mb-4 block">Taste perception</span>
<h3 className="font-display text-2xl lg:text-3xl font-black text-white tracking-widest uppercase mb-6 leading-tight">
Traditional
<br />
& Modern
</h3>
<p className="text-white/50 font-sans-clean text-xs leading-relaxed max-w-xs mb-8">
Palermonun en eski geleneksel tekniklerini modern gastronomi vizyonuyla harmanlıyoruz. Her ayrıntıda yüksek zanaatkarlık yatıyor.
</p>
<motion.button
onClick={() => setShowBookingModal(true)}
className="text-[10px] font-sans-clean font-bold tracking-[2px] uppercase text-[#C5A880] border border-[#C5A880]/40 hover:border-[#C5A880] px-5 py-3 rounded-lg transition-colors cursor-pointer"
whileHover={{ scale: 1.04 }}
>
Read More
</motion.button>
</div>
<div className="bg-[#13151A] rounded-2xl p-10 border border-[#C5A880]/10 flex flex-col items-center justify-center text-center shadow-2xl relative">
<span className="text-[#C5A880] text-xs tracking-wider mb-4 block">Crafted Flavours</span>
<h3 className="font-display text-2xl lg:text-3xl font-black text-white tracking-widest uppercase mb-6 leading-tight">
Wood &amp; Fire
</h3>
<p className="text-white/50 font-sans-clean text-xs leading-relaxed max-w-xs">
Ustalık gerektiren fırınlama ve pişirme aşamalarından geçerek servis edilen tabaklarımız, damak tadınızda unutulmaz izler bırakır.
</p>
</div>
<div className="bg-[#13151A] rounded-2xl p-10 border border-[#C5A880]/10 flex flex-col items-center justify-center text-center shadow-2xl relative">
<span className="text-[#C5A880] text-xs tracking-wider mb-4 block">Atmosphere</span>
<h3 className="font-display text-2xl lg:text-3xl font-black text-white tracking-widest uppercase mb-6 leading-tight">
Refined Space
</h3>
<p className="text-white/50 font-sans-clean text-xs leading-relaxed max-w-xs">
Özenle dekore edilmiş loş, taş döşemeli şık salonumuzda kendinizi İtalya sokaklarında hissedeceksiniz.
</p>
</div>
</div>
</div>
</section>
{/* ── SECTION 3: SPECIAL MEAL ── */}
<section id="special-meal" className="py-32 bg-[#0E0F12] border-t border-[#C5A880]/15 relative z-10 px-6">
<div className="max-w-6xl mx-auto">
<div className="text-center mb-16">
<span className="text-[#C5A880] font-display italic text-base tracking-wider block mb-4">our full menu</span>
<h2 className="font-display text-4xl lg:text-5xl font-black tracking-widest text-white uppercase mb-16">
Special Meal
</h2>
</div>
<div className="grid lg:grid-cols-12 gap-16 items-start">
<div className="lg:col-span-12 flex flex-col justify-center">
<div className="space-y-6 max-w-4xl mx-auto w-full">
{menu[aktifKategori]?.urunler.map((item) => (
<div key={item.ad} className="flex flex-col cursor-pointer group">
<div className="flex items-end justify-between gap-4">
<span className="font-display text-base lg:text-lg font-bold text-white group-hover:text-[#C5A880] transition-colors uppercase">
{item.ad}
</span>
<div className="grow border-b border-dashed border-[#C5A880]/20 mb-2 group-hover:border-[#C5A880]/40 transition-colors mx-2" />
<span className="font-display text-base font-black text-[#C5A880] shrink-0">
{item.fiyat}
</span>
</div>
<p className="text-white/50 font-sans-clean text-[11px] mt-1 leading-relaxed">
{item.aciklama}
</p>
</div>
))}
</div>
{/* Category Tab Buttons */}
<div className="flex items-center justify-center gap-4 mt-16 flex-wrap">
{menu.map((kat, idx) => (
<button
key={kat.kategori}
onClick={() => setAktifKategori(idx)}
className="text-[10px] font-sans-clean font-bold tracking-[2px] uppercase px-5 py-3 rounded-lg border transition-all cursor-pointer"
style={aktifKategori === idx
? { backgroundColor: "#C5A880", color: "#090A0C", borderColor: "#C5A880" }
: { backgroundColor: "transparent", color: "rgba(255,255,255,0.5)", borderColor: "rgba(197,168,128,0.2)" }
}
>
{kat.kategori}
</button>
))}
</div>
</div>
</div>
</div>
</section>
{/* ── SECTION 5: SERVICES ── */}
<section id="services" className="py-24 bg-[#090A0C] border-t border-[#C5A880]/15 relative z-10 px-6">
<div className="max-w-7xl mx-auto">
<div className="text-center mb-16">
<span className="text-[#C5A880] font-display italic text-base tracking-wider block mb-3">Our Offerings</span>
<h2 className="font-display text-3xl lg:text-4xl font-black tracking-widest text-white uppercase">
Hizmetlerimiz
</h2>
</div>
<div className="grid md:grid-cols-4 gap-6">
{hizmetler.map((h, i) => (
<motion.div
key={h.baslik}
className="bg-[#13151A] rounded-xl p-8 border border-white/5 hover:border-[#C5A880]/30 hover:bg-[#13151A]/80 transition-all duration-300 flex flex-col items-center text-center group cursor-default"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: i * 0.1 }}
whileHover={{ y: -4 }}
>
<div className="w-14 h-14 rounded-xl bg-white/5 border border-white/10 flex items-center justify-center mb-5 transition-all group-hover:bg-[#C5A880]/10 group-hover:border-[#C5A880]/30">
{getIconSvg(h.ikon)}
</div>
<h3 className="font-display font-bold text-white text-sm mb-3 uppercase tracking-wider leading-snug">
{h.baslik}
</h3>
<p className="text-white/50 font-sans-clean text-[10px] leading-relaxed">
{h.aciklama}
</p>
</motion.div>
))}
</div>
</div>
</section>
{/* ── SECTION 6: TESTIMONIALS ── */}
<section id="yorumlar" className="py-28 bg-[#0E0F12] border-t border-[#C5A880]/15 px-6">
<div className="max-w-7xl mx-auto">
<div className="text-center mb-16">
<span className="text-[#C5A880] font-display italic text-base tracking-wider block mb-3">social proof</span>
<h2 className="font-display text-3xl lg:text-4xl font-black tracking-widest text-white uppercase">
Misafir Deneyimleri
</h2>
</div>
<div className="grid md:grid-cols-3 gap-6">
{yorumlar.map((y, i) => (
<motion.div
key={y.yazar}
className="bg-[#13151A] border border-[#C5A880]/10 rounded-xl p-8 flex flex-col justify-between"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: i * 0.1 }}
whileHover={{ y: -4, borderColor: "rgba(197,168,128,0.3)" }}
>
<div className="flex gap-1 mb-6">
{[...Array(y.puan)].map((_, j) => (
<span key={j} className="text-[#C5A880]"></span>
))}
</div>
<p className="text-white/80 font-sans-clean text-xs leading-relaxed italic mb-8">
&ldquo;{y.yorum}&rdquo;
</p>
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full border border-[#C5A880]/30 flex items-center justify-center text-lg bg-[#090A0C] shrink-0">
{y.emoji}
</div>
<div>
<h4 className="font-display text-[#C5A880] text-xs font-bold uppercase tracking-wider">
{y.yazar}
</h4>
<span className="font-sans-clean text-[9px] text-white/40 uppercase tracking-widest">
{y.tarih}
</span>
</div>
</div>
</motion.div>
))}
</div>
</div>
</section>
{/* ── SECTION 7: RESERVATION ── */}
<section id="randevu" className="py-32 bg-[#090A0C] border-t border-[#C5A880]/15 relative z-10 px-6">
<div className="max-w-3xl mx-auto">
<div className="bg-[#13151A] rounded-2xl p-8 md:p-12 shadow-2xl border border-[#C5A880]/20">
<div className="text-center mb-10">
<span className="text-[#C5A880] font-display italic text-base tracking-wider block mb-3">booking reservation</span>
<h2 className="font-display text-3xl md:text-4xl font-black tracking-widest text-white uppercase">
Masa Rezervasyonu
</h2>
<p className="text-white/60 font-sans-clean text-xs mt-2 leading-relaxed">
Benzersiz bir fine dining deneyimi için masanızı önceden ayırtın.
</p>
</div>
<div className="grid grid-cols-2 gap-5">
{[
{ label: "Ad Soyad", placeholder: "Adınız Soyadınız", type: "text", full: false },
{ label: "Telefon", placeholder: "05xx xxx xx xx", type: "tel", full: false },
{ label: "Tarih", placeholder: "", type: "date", full: false },
{ label: "Saat", placeholder: "", type: "time", full: false },
{ label: "Kişi Sayısı", placeholder: "2", type: "number", full: false },
{ label: "Özel İstek / Not", placeholder: "Diyet hassasiyetleri, kutlamalar vb.", type: "text", full: true },
].map((field, i) => (
<div key={i} className={field.full ? "col-span-2" : "col-span-1"}>
<label className="block text-[9px] font-sans-clean font-bold text-[#C5A880] mb-1.5 uppercase tracking-widest">{field.label}</label>
<input
type={field.type}
placeholder={field.placeholder}
className="w-full px-4 py-3 rounded-xl border border-white/10 bg-[#090A0C] text-sm text-white focus:outline-none focus:ring-1 focus:ring-[#C5A880] placeholder-white/20 transition-all font-sans-clean"
/>
</div>
))}
</div>
<motion.button
className="mt-8 w-full py-4 rounded-xl text-[#090A0C] font-sans-clean font-black tracking-[2px] uppercase bg-[#C5A880] hover:bg-[#D5B990] transition-colors cursor-pointer text-xs"
whileHover={{ scale: 1.02, boxShadow: "0 10px 30px rgba(197, 168, 128, 0.25)" }}
whileTap={{ scale: 0.98 }}
>
Masa Ayırt
</motion.button>
</div>
</div>
</section>
{/* ── FOOTER ── */}
<footer className="bg-[#090A0C] border-t border-white/5 px-6 pt-20 pb-8 relative z-10">
<div className="max-w-7xl mx-auto">
<div className="grid md:grid-cols-4 gap-12 pb-16 border-b border-white/5">
<div className="md:col-span-2">
<span className="font-display text-2xl font-black text-[#C5A880] tracking-widest uppercase mb-4 block">
{firma.adi}
</span>
<p className="text-white/60 font-sans-clean text-xs leading-relaxed max-w-xs mb-8">
{firma.slogan} Geleneksel zanaat, modern vizyon.
</p>
<p className="text-white/60 font-sans-clean text-xs">📍 {firma.adres}</p>
<p className="text-white/60 font-sans-clean text-xs mt-1">📞 {firma.telefon}</p>
</div>
<div>
<h4 className="font-display text-white text-xs font-bold uppercase tracking-wider mb-5">
Şefin Menüsü
</h4>
{menu.map(kat => (
<a
key={kat.kategori}
href="#special-meal"
className="block text-white/50 hover:text-white text-xs mb-2.5 transition-colors font-sans-clean uppercase tracking-wider"
>
{kat.kategori}
</a>
))}
</div>
<div>
<h4 className="font-display text-white text-xs font-bold uppercase tracking-wider mb-5">
Karaköy Lezzet
</h4>
{["Heritage", "Special Meal", "Reservation"].map(item => (
<a
key={item}
href="#"
className="block text-white/50 hover:text-white text-xs mb-2.5 transition-colors font-sans-clean"
>
{item}
</a>
))}
</div>
</div>
<div className="flex flex-col md:flex-row justify-between items-center pt-8 gap-4 font-sans-clean text-white/40">
<p className="text-xs">© 2026 {firma.adi}. Tüm hakları saklıdır.</p>
<p className="text-[10px]">Gizlilik Politikası · Çerez Ayarları</p>
</div>
</div>
</footer>
{/* ── FAST BOOKING OVERLAY MODAL ── */}
<AnimatePresence>
{showBookingModal && (
<motion.div
className="fixed inset-0 z-50 flex items-center justify-center p-6 bg-black/80 backdrop-blur-sm"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
<motion.div
className="bg-[#13151A] rounded-2xl p-8 max-w-md w-full relative shadow-2xl border border-[#C5A880]/30"
initial={{ scale: 0.95, y: 20 }}
animate={{ scale: 1, y: 0 }}
exit={{ scale: 0.95, y: 20 }}
>
<button
className="absolute top-6 right-6 w-8 h-8 rounded-full bg-white/5 flex items-center justify-center text-white/60 hover:text-white transition-colors"
onClick={() => setShowBookingModal(false)}
>
</button>
<h3 className="font-display font-black text-white text-xl mb-1 uppercase tracking-wider">
Hızlı Rezervasyon
</h3>
<p className="text-white/50 font-sans-clean text-[10px] mb-6 uppercase tracking-widest">
Karaköy Rezervasyon Hattı
</p>
<div className="space-y-4">
<div>
<label className="block text-[9px] font-sans-clean font-bold text-[#C5A880] mb-1 uppercase tracking-wider">Ad Soyad</label>
<input type="text" className="w-full px-4 py-3 rounded-xl border border-white/10 bg-[#090A0C] text-sm text-white focus:outline-none focus:ring-1 focus:ring-[#C5A880]" placeholder="Adınız Soyadınız" />
</div>
<div>
<label className="block text-[9px] font-sans-clean font-bold text-[#C5A880] mb-1 uppercase tracking-wider">Telefon Numarası</label>
<input type="tel" className="w-full px-4 py-3 rounded-xl border border-white/10 bg-[#090A0C] text-sm text-white focus:outline-none focus:ring-1 focus:ring-[#C5A880]" placeholder="05xx xxx xx xx" />
</div>
<motion.button
className="w-full py-4 rounded-xl bg-[#C5A880] text-[#090A0C] font-sans-clean font-black text-xs uppercase tracking-wider mt-4"
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
onClick={() => setShowBookingModal(false)}
>
Bilgileri Gönder
</motion.button>
</div>
</motion.div>
</motion.div>
)}
</AnimatePresence>
</div>
);
}
+460
View File
@@ -0,0 +1,460 @@
"use client";
import { motion, useScroll, useTransform, AnimatePresence } from "framer-motion";
import { useRef, useState } from "react";
import type { DemoData } from "@/data/demos";
import AnimatedCounter from "@/components/ui/AnimatedCounter";
const easeOutExpo = [0.16, 1, 0.3, 1] as [number, number, number, number];
const fadeUp = {
hidden: { opacity: 0, y: 40 },
show: { opacity: 1, y: 0, transition: { duration: 0.7, ease: easeOutExpo } },
};
const stagger = {
hidden: {},
show: { transition: { staggerChildren: 0.1 } },
};
export default function RestoranTemplate2({ data }: { data: DemoData }) {
const { firma, istatistikler, hizmetler, menu = [], yorumlar = [] } = data;
const heroRef = useRef<HTMLDivElement>(null);
const { scrollYProgress } = useScroll({ target: heroRef, offset: ["start start", "end start"] });
const heroY = useTransform(scrollYProgress, [0, 1], ["0%", "20%"]);
const heroOpacity = useTransform(scrollYProgress, [0, 0.8], [1, 0]);
const [aktifKategori, setAktifKategori] = useState(0);
const [showBookingModal, setShowBookingModal] = useState(false);
// SVG Render Helper for clean vector icons (No Emojis)
const getIconSvg = (name: string) => {
switch (name) {
case "alacarte":
return (
<svg className="w-6 h-6 stroke-[#0038A8]" viewBox="0 0 24 24" fill="none" strokeWidth="1.5">
<path strokeLinecap="round" strokeLinejoin="round" d="M12 6.042A8.967 8.967 0 0 0 6 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 0 1 6 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 0 1 6-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0 0 18 18a8.967 8.967 0 0 0-6 2.292m0-14.25v14.25" />
</svg>
);
case "special":
return (
<svg className="w-6 h-6 stroke-[#0038A8]" viewBox="0 0 24 24" fill="none" strokeWidth="1.5">
<path strokeLinecap="round" strokeLinejoin="round" 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>
);
case "catering":
return (
<svg className="w-6 h-6 stroke-[#0038A8]" viewBox="0 0 24 24" fill="none" strokeWidth="1.5">
<path strokeLinecap="round" strokeLinejoin="round" d="M12 3v18M3 12h18" />
</svg>
);
case "delivery":
return (
<svg className="w-6 h-6 stroke-[#0038A8]" viewBox="0 0 24 24" fill="none" strokeWidth="1.5">
<path strokeLinecap="round" strokeLinejoin="round" d="M8.25 18.75a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0ZM19.5 18.75a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0Z" />
<path strokeLinecap="round" strokeLinejoin="round" d="M2.25 3h1.386c.51 0 .955.343 1.087.835l.383 1.437M7.5 14.25a3 3 0 0 0-3 3h15.75" />
</svg>
);
default:
return (
<svg className="w-6 h-6 stroke-[#0038A8]" viewBox="0 0 24 24" fill="none" strokeWidth="1.5">
<path strokeLinecap="round" d="M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21" />
</svg>
);
}
};
return (
<div className="bg-[#FDFBF7] text-[#121C22] font-body">
{/* ── HEADER ── */}
<motion.header
className="fixed top-4 left-4 right-4 z-50 px-4"
initial={{ y: -80, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ duration: 0.7, ease: easeOutExpo }}
>
<div className="mx-auto max-w-7xl h-20 flex items-center justify-between px-8 bg-[#FDFBF7]/90 backdrop-blur-xl border border-[#0038A8]/10 rounded-2xl shadow-lg">
<a href="#" className="flex items-center gap-2">
<span className="text-xl font-bold tracking-tight text-[#0038A8] font-display flex items-center gap-1.5 uppercase">
<span className="text-2xl">🍋</span> {firma.adi}
</span>
</a>
<nav className="hidden lg:flex items-center gap-8">
{[
{ label: "Our Story", href: "#story" },
{ label: "Pasta & Pizza", href: "#pasta-pizza" },
{ label: "Lemon Orchard", href: "#lemon" },
{ label: "Hizmetlerimiz", href: "#services" },
{ label: "Rezervasyon", href: "#randevu" }
].map(item => (
<a
key={item.label}
href={item.href}
className="text-[11px] font-sans-clean font-bold tracking-[1.5px] uppercase text-[#0038A8]/70 hover:text-[#0038A8] transition-colors"
>
{item.label}
</a>
))}
</nav>
<div className="flex items-center gap-4">
<motion.button
onClick={() => setShowBookingModal(true)}
className="text-[11px] font-sans-clean font-black tracking-[2px] uppercase text-white bg-[#0038A8] hover:bg-[#002266] px-6 py-3 rounded-xl transition-all cursor-pointer shadow-md shadow-[#0038A8]/20"
whileHover={{ scale: 1.03 }}
whileTap={{ scale: 0.98 }}
>
Book Table
</motion.button>
</div>
</div>
</motion.header>
{/* ── HERO SECTION ── */}
<section ref={heroRef} className="relative min-h-screen flex items-center bg-[#FDFBF7] pt-24">
<div className="relative z-10 max-w-7xl mx-auto px-6 w-full py-12">
<div className="grid lg:grid-cols-12 gap-12 items-center">
{/* Left Content */}
<motion.div
className="lg:col-span-12 z-20 text-center"
variants={stagger}
initial="hidden"
animate="show"
>
<motion.div
variants={fadeUp}
className="inline-flex items-center gap-2 text-[10px] font-sans-clean font-black uppercase tracking-widest text-[#0038A8]/60 mb-6 bg-[#0038A8]/5 border border-[#0038A8]/10 px-4 py-2 rounded-full"
>
<span className="w-1.5 h-1.5 rounded-full bg-[#0038A8]" />
{firma.slogan}
</motion.div>
<motion.h1
variants={fadeUp}
className="font-display text-6xl md:text-7xl font-black text-[#0038A8] leading-[1.05] tracking-tight mb-8"
>
Linen, Lemons
<br />
<span className="italic font-light opacity-90 text-[#3C5A48]">&amp; Wood-fired</span>
</motion.h1>
<motion.p
variants={fadeUp}
className="text-gray-600 font-sans-clean text-sm lg:text-base leading-relaxed max-w-md mx-auto mb-12 font-medium"
>
Karaköy limanında, Sicilya rüzgarları esiyor. El yapımı makarnalar, taze baharatlar ve odun ateşinde karamelize olan lezzetler.
</motion.p>
<motion.div variants={fadeUp}>
<motion.a
href="#pasta-pizza"
className="inline-flex items-center gap-3 px-8 py-4 rounded-full bg-[#0038A8] hover:bg-[#002266] text-white font-sans-clean font-black text-xs transition-all shadow-lg shadow-[#0038A8]/30 cursor-pointer"
whileHover={{ scale: 1.04 }}
whileTap={{ scale: 0.97 }}
>
Discover Menu <span className="text-[10px]"></span>
</motion.a>
</motion.div>
</motion.div>
</div>
</div>
</section>
{/* ── SECTION 2: OUR STORY ── */}
<section id="story" className="py-32 bg-[#F5F2EB] px-6 relative z-10 border-t border-[#0038A8]/5">
<div className="max-w-7xl mx-auto">
<div className="grid lg:grid-cols-12 gap-16 items-center">
<motion.div
className="lg:col-span-12 text-center"
initial="hidden"
whileInView="show"
viewport={{ once: true, amount: 0.2 }}
variants={stagger}
>
<motion.span
variants={fadeUp}
className="text-[#0038A8] font-display italic text-base tracking-wider block mb-4"
>
Sicilian Baking Heritage
</motion.span>
<motion.h2
variants={fadeUp}
className="font-display text-4xl lg:text-5xl font-black tracking-tight text-[#0038A8] uppercase mb-8"
>
Our Story
</motion.h2>
<motion.p
variants={fadeUp}
className="text-gray-600 font-sans-clean text-xs leading-relaxed mb-12 max-w-md mx-auto font-medium"
>
Odun ateşinin alevi ve zeytin ağacı közlerinin aroması. Sicilia Tavola, nesiller boyu aktarılan İtalyan tariflerini zanaatkar ellerle buluşturuyor. Her pizza taş fırınımızda 485 derecede saniyeler içinde mükemmelleşiyor.
</motion.p>
{/* Grid Metrics */}
<motion.div
variants={fadeUp}
className="grid grid-cols-2 sm:grid-cols-4 gap-4 max-w-4xl mx-auto"
>
{istatistikler.map((s, i) => (
<div key={i} className="bg-white p-6 rounded-2xl border border-[#0038A8]/5">
<div className="text-3xl font-black text-[#0038A8] font-display">
{s.deger}
</div>
<div className="text-gray-400 text-[10px] uppercase font-sans-clean font-bold tracking-widest mt-1">
{s.etiket}
</div>
</div>
))}
</motion.div>
</motion.div>
</div>
</div>
</section>
{/* ── SECTION 3: PASTA & PIZZA MENU ── */}
<section id="pasta-pizza" className="py-32 bg-[#FDFBF7] relative z-10 px-6 border-t border-[#0038A8]/5">
<div className="max-w-6xl mx-auto">
<div className="text-center mb-16">
<span className="text-[#0038A8] font-display italic text-base tracking-wider block mb-4">our fresh selections</span>
<h2 className="font-display text-4xl lg:text-5xl font-black tracking-tight text-[#0038A8] uppercase mb-16">
Pasta &amp; Pizza
</h2>
</div>
<div className="space-y-6 max-w-3xl mx-auto w-full">
{menu[aktifKategori]?.urunler.map((item) => (
<div key={item.ad} className="flex flex-col cursor-pointer group">
<div className="flex items-end justify-between gap-4">
<span className="font-display text-base lg:text-lg font-bold text-[#0038A8] group-hover:opacity-85 transition-opacity uppercase">
{item.ad}
</span>
<div className="grow border-b border-dashed border-[#0038A8]/20 mb-2 transition-colors mx-2" />
<span className="font-display text-base font-black text-[#0038A8] shrink-0">
{item.fiyat}
</span>
</div>
<p className="text-gray-500 font-sans-clean text-[11px] mt-1 leading-relaxed">
{item.aciklama}
</p>
</div>
))}
</div>
{/* Category Tab Buttons */}
<div className="flex items-center justify-center gap-4 mt-16 flex-wrap">
{menu.map((kat, idx) => (
<button
key={kat.kategori}
onClick={() => setAktifKategori(idx)}
className="text-[10px] font-sans-clean font-bold tracking-[1.5px] uppercase px-5 py-3 rounded-lg border transition-all cursor-pointer"
style={aktifKategori === idx
? { backgroundColor: "#0038A8", color: "white", borderColor: "#0038A8" }
: { backgroundColor: "transparent", color: "rgba(0, 56, 168, 0.6)", borderColor: "rgba(0, 56, 168, 0.2)" }
}
>
{kat.kategori}
</button>
))}
</div>
</div>
</section>
{/* ── SECTION 5: SERVICES ── */}
<section id="services" className="py-24 bg-[#FDFBF7] border-t border-[#0038A8]/5 relative z-10 px-6">
<div className="max-w-7xl mx-auto">
<div className="text-center mb-16">
<span className="text-[#0038A8] font-display italic text-base tracking-wider block mb-3">Our Offerings</span>
<h2 className="font-display text-3xl lg:text-4xl font-black tracking-tight text-[#0038A8] uppercase">
Hizmetlerimiz
</h2>
</div>
<div className="grid md:grid-cols-4 gap-6">
{hizmetler.map((h, i) => (
<motion.div
key={h.baslik}
className="bg-white rounded-2xl p-8 border border-[#0038A8]/5 hover:border-[#0038A8]/30 hover:bg-[#FDFBF7] transition-all duration-300 flex flex-col items-center text-center group cursor-default shadow-sm"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: i * 0.1 }}
whileHover={{ y: -4 }}
>
<div className="w-14 h-14 rounded-full bg-[#0038A8]/5 flex items-center justify-center mb-5 transition-transform group-hover:scale-110">
{getIconSvg(h.ikon)}
</div>
<h3 className="font-display font-bold text-[#0038A8] text-sm mb-3 uppercase tracking-wider leading-snug">
{h.baslik}
</h3>
<p className="text-gray-400 font-sans-clean text-[10px] leading-relaxed">
{h.aciklama}
</p>
</motion.div>
))}
</div>
</div>
</section>
{/* ── SECTION 6: TESTIMONIALS ── */}
<section id="yorumlar" className="py-28 bg-[#F5F2EB] border-t border-[#0038A8]/5 px-6">
<div className="max-w-7xl mx-auto">
<div className="text-center mb-16">
<span className="text-[#0038A8] font-display italic text-base tracking-wider block mb-3">guest stories</span>
<h2 className="font-display text-3xl lg:text-4xl font-black tracking-tight text-[#0038A8] uppercase">
Misafir Yorumları
</h2>
</div>
<div className="grid md:grid-cols-2 gap-8 max-w-4xl mx-auto">
{yorumlar.map((y, i) => (
<motion.div
key={y.yazar}
className="bg-white border border-[#0038A8]/5 rounded-[28px] p-8 flex flex-col justify-between shadow-sm"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: i * 0.1 }}
whileHover={{ y: -4, borderColor: "rgba(0, 56, 168, 0.3)" }}
>
<div className="flex gap-1 mb-6">
{[...Array(y.puan)].map((_, j) => (
<span key={j} className="text-[#0038A8]"></span>
))}
</div>
<p className="text-gray-600 font-sans-clean text-xs leading-relaxed italic mb-8 font-medium">
&ldquo;{y.yorum}&rdquo;
</p>
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full border border-[#0038A8]/20 flex items-center justify-center text-lg bg-[#FDFBF7] shrink-0 shadow-sm">
{y.emoji}
</div>
<div>
<h4 className="font-display text-[#0038A8] text-xs font-bold uppercase tracking-wider">
{y.yazar}
</h4>
<span className="font-sans-clean text-[9px] text-gray-400 uppercase tracking-widest">
{y.tarih}
</span>
</div>
</div>
</motion.div>
))}
</div>
</div>
</section>
{/* ── SECTION 7: RESERVATION ── */}
<section id="randevu" className="py-32 bg-[#FDFBF7] border-t border-[#0038A8]/5 relative z-10 px-6">
<div className="max-w-3xl mx-auto">
<div className="bg-white rounded-[36px] p-8 md:p-12 shadow-2xl border border-[#0038A8]/10">
<div className="text-center mb-10">
<span className="text-[#0038A8] font-display italic text-base tracking-wider block mb-3">Tavola Reservation</span>
<h2 className="font-display text-3xl md:text-4xl font-black tracking-tight text-[#0038A8] uppercase">
Masa Rezervasyonu
</h2>
<p className="text-gray-400 font-sans-clean text-xs mt-2 leading-relaxed font-medium">
Karaköy Trattoria&apos;mızda unutulmaz bir akşam yemeği için yerinizi ayırtın.
</p>
</div>
<div className="grid grid-cols-2 gap-5">
{[
{ label: "Ad Soyad", placeholder: "Adınız Soyadınız", type: "text", full: false },
{ label: "Telefon", placeholder: "05xx xxx xx xx", type: "tel", full: false },
{ label: "Tarih", placeholder: "", type: "date", full: false },
{ label: "Saat", placeholder: "", type: "time", full: false },
{ label: "Kişi Sayısı", placeholder: "2", type: "number", full: false },
{ label: "Özel Notlar", placeholder: "Diyet sınırlandırmaları veya özel kutlamalar...", type: "text", full: true },
].map((field, i) => (
<div key={i} className={field.full ? "col-span-2" : "col-span-1"}>
<label className="block text-[9px] font-sans-clean font-bold text-[#0038A8] mb-1.5 uppercase tracking-widest">{field.label}</label>
<input
type={field.type}
placeholder={field.placeholder}
className="w-full px-4 py-3 rounded-xl border border-gray-200 bg-[#FDFBF7] text-sm text-[#121C22] focus:outline-none focus:ring-1 focus:ring-[#0038A8] placeholder-gray-300 transition-all font-sans-clean"
/>
</div>
))}
</div>
<motion.button
className="mt-8 w-full py-4 rounded-xl text-white font-sans-clean font-black tracking-[2px] uppercase bg-[#0038A8] hover:bg-[#002266] transition-colors cursor-pointer text-xs"
whileHover={{ scale: 1.02, boxShadow: "0 10px 30px rgba(0, 56, 168, 0.25)" }}
whileTap={{ scale: 0.98 }}
>
Masa Ayırt
</motion.button>
</div>
</div>
</section>
{/* ── FOOTER ── */}
<footer className="bg-[#002266] text-white border-t border-white/5 px-6 pt-20 pb-8 relative z-10">
<div className="max-w-6xl mx-auto flex flex-col sm:flex-row justify-between items-center pt-8 gap-4 font-sans-clean text-white/40">
<p className="text-xs">© 2026 {firma.adi}. Tüm hakları saklıdır.</p>
<p className="text-[10px]">Gizlilik Politikası · Çerez Ayarları</p>
</div>
</footer>
{/* ── FAST BOOKING OVERLAY MODAL ── */}
<AnimatePresence>
{showBookingModal && (
<motion.div
className="fixed inset-0 z-50 flex items-center justify-center p-6 bg-black/60 backdrop-blur-sm"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
<motion.div
className="bg-white rounded-2xl p-8 max-w-md w-full relative shadow-2xl border border-[#0038A8]/20"
initial={{ scale: 0.95, y: 20 }}
animate={{ scale: 1, y: 0 }}
exit={{ scale: 0.95, y: 20 }}
>
<button
className="absolute top-6 right-6 w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center text-gray-500 hover:bg-gray-200 transition-colors"
onClick={() => setShowBookingModal(false)}
>
</button>
<h3 className="font-display font-black text-[#0038A8] text-xl mb-1 uppercase tracking-wider">
Hızlı Rezervasyon
</h3>
<p className="text-gray-400 font-sans-clean text-[10px] mb-6 uppercase tracking-widest font-semibold">
Karaköy Trattoria Hattı
</p>
<div className="space-y-4">
<div>
<label className="block text-[9px] font-sans-clean font-bold text-[#0038A8] mb-1 uppercase tracking-wider">Ad Soyad</label>
<input type="text" className="w-full px-4 py-3 rounded-xl border border-gray-200 bg-[#FDFBF7] text-sm focus:outline-none focus:ring-1 focus:ring-[#0038A8]" placeholder="Adınız Soyadınız" />
</div>
<div>
<label className="block text-[9px] font-sans-clean font-bold text-[#0038A8] mb-1 uppercase tracking-wider">Telefon Numarası</label>
<input type="tel" className="w-full px-4 py-3 rounded-xl border border-gray-200 bg-[#FDFBF7] text-sm focus:outline-none focus:ring-1 focus:ring-[#0038A8]" placeholder="05xx xxx xx xx" />
</div>
<motion.button
className="w-full py-4 rounded-xl bg-[#0038A8] text-white font-sans-clean font-black text-xs uppercase tracking-wider mt-4"
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
onClick={() => setShowBookingModal(false)}
>
Bilgileri Gönder
</motion.button>
</div>
</motion.div>
</motion.div>
)}
</AnimatePresence>
</div>
);
}
+34
View File
@@ -0,0 +1,34 @@
"use client";
import { useEffect, useRef, useState } from "react";
import { useInView } from "framer-motion";
export default function AnimatedCounter({ target, suffix = "" }: { target: number; suffix?: string }) {
const [count, setCount] = useState(0);
const ref = useRef(null);
const inView = useInView(ref, { once: true });
useEffect(() => {
if (!inView) return;
const duration = 1800;
const steps = 60;
const increment = target / steps;
let current = 0;
const timer = setInterval(() => {
current += increment;
if (current >= target) {
setCount(target);
clearInterval(timer);
} else {
setCount(Math.floor(current));
}
}, duration / steps);
return () => clearInterval(timer);
}, [inView, target]);
return (
<span ref={ref}>
{count.toLocaleString("tr-TR")}
{suffix}
</span>
);
}