initial commit: project completion with proper gitignore

This commit is contained in:
AyrisAI
2026-05-16 00:43:22 +03:00
commit e708ba2156
84 changed files with 11035 additions and 0 deletions

65
components/BottomBar.tsx Normal file
View File

@@ -0,0 +1,65 @@
"use client";
import { Instagram, Twitter } from "lucide-react";
import Link from "next/link";
interface StatItemProps {
icon: React.ReactNode;
label: string;
sublabel: string;
}
function StatItem({ icon, label, sublabel }: StatItemProps) {
return (
<div className="glass p-4 rounded-2xl flex items-center gap-4 min-w-[200px]">
<div className="w-10 h-10 glass rounded-lg flex items-center justify-center text-white/40">
{icon}
</div>
<div>
<h4 className="text-white font-bold text-sm leading-tight">{label}</h4>
<p className="text-white/40 text-[10px] font-medium">{sublabel}</p>
</div>
</div>
);
}
export default function BottomBar() {
return (
<div className="absolute bottom-0 left-0 w-full px-6 md:px-8 py-6 md:py-10 flex flex-col md:flex-row items-center md:items-end justify-between gap-6 pointer-events-none">
{/* Stats Section - Hidden on mobile */}
<div className="hidden md:flex items-center gap-4 pointer-events-auto">
<StatItem
icon={<div className="text-[#1e9a83]">📸</div>}
label="500+"
sublabel="Tamamlanan Çekim"
/>
<StatItem
icon={<div className="text-[#1e9a83]">🏢</div>}
label="150+"
sublabel="Mutlu Müşteri"
/>
<StatItem
icon={<div className="text-[#1e9a83]">🚁</div>}
label="Drone"
sublabel="Profesyonel Çekim"
/>
</div>
{/* Socials & Scroll Section */}
<div className="flex flex-col items-center md:items-end gap-4 md:gap-6 pointer-events-auto mb-2">
<div className="flex items-center gap-6">
<span className="text-[10px] font-bold tracking-[0.2em] text-white/30 uppercase">Bizi Takip Edin</span>
<div className="flex items-center gap-4 text-white/60">
<Link href="#" className="hover:text-white transition-colors"><Instagram className="w-4 h-4" /></Link>
<Link href="#" className="hover:text-white transition-colors"><Twitter className="w-4 h-4" /></Link>
</div>
</div>
</div>
{/* Copyright */}
<div className="md:absolute md:bottom-4 md:left-8 text-[10px] text-white/20 font-medium text-center md:text-left">
© {new Date().getFullYear()} Muğla Dijital Medya Ajansı. Tüm hakları saklıdır.
</div>
</div>
);
}

View File

@@ -0,0 +1,83 @@
"use client";
import { useEffect, useState } from "react";
import { getFeaturedServices } from "@/app/actions";
import * as LucideIcons from "lucide-react";
import {
ArrowRight,
Layers
} from "lucide-react";
import Link from "next/link";
export default function Capabilities() {
const [services, setServices] = useState<any[]>([]);
useEffect(() => {
async function fetchServices() {
const data = await getFeaturedServices();
if (data && data.length > 0) {
setServices(data);
}
}
fetchServices();
}, []);
const DynamicIcon = ({ name, className }: { name: string, className?: string }) => {
const IconComponent = (LucideIcons as any)[name] || Layers;
return <IconComponent className={className} />;
};
// Fallback static data if database is empty
const displayData = services.length > 0 ? services : [
{ title: "Art Direction", description: "Conceptualizing visual narratives that resonate. We define the look and feel before the camera even rolls.", icon_name: "Palette" },
{ title: "Cinematography", description: "Capturing light and shadow with state-of-the-art gear. 8K workflows and cinema-grade optics.", icon_name: "Video" },
{ title: "Motion Graphics", description: "Adding kinetic energy to static visuals. 2D and 3D animation that enhances the storytelling.", icon_name: "Clapperboard" },
{ title: "Color Grading", description: "Setting the mood with precise color science. We ensure your visuals look perfect on every screen.", icon_name: "Contrast" }
];
return (
<section className="py-16 md:py-24 px-6 md:px-16 lg:px-24">
<div className="max-w-7xl mx-auto flex flex-col lg:flex-row gap-8 md:gap-16 items-start">
{/* Left Content */}
<div className="lg:w-1/3">
<h2 className="text-4xl md:text-5xl font-bold mb-6 text-white italic tracking-tighter uppercase">Yeteneklerimiz</h2>
<p className="text-white/60 text-lg mb-8 leading-relaxed">
Fikir aşamasından final renk düzenlemesine kadar, görsel üretim sürecinin her adımını takıntılı derecede yüksek standartlarla yönetiyoruz.
</p>
<Link
href="/services"
className="group flex items-center gap-2 text-[#1e9a83] font-semibold hover:text-white transition-colors"
>
Tüm Hizmetleri Gör
<ArrowRight className="w-4 h-4 group-hover:translate-x-1 transition-transform" />
</Link>
</div>
{/* Right Grid - Restored to Original Design */}
<div className="lg:w-2/3 w-full border border-white/10 rounded-3xl overflow-hidden grid grid-cols-1 md:grid-cols-2">
{services.map((service, index) => (
<div
key={service.id || index}
className={`p-10 flex flex-col gap-4 hover:bg-white/[0.02] transition-colors border-white/10
${index === 0 ? "border-b md:border-r" : ""}
${index === 1 ? "border-b md:border-b" : ""}
${index === 2 ? "md:border-r border-b md:border-b-0" : ""}
${index === 3 ? "" : ""}
`}
>
<div className="w-12 h-12 rounded-xl bg-[#1e9a83]/10 flex items-center justify-center text-[#1e9a83]">
<DynamicIcon name={service.icon_name} className="w-6 h-6" />
</div>
<h3 className="text-xl font-bold text-white mt-2 uppercase italic tracking-tight">{service.title}</h3>
<p className="text-white/40 leading-relaxed text-sm font-medium">
{service.description}
</p>
</div>
))}
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,16 @@
"use client";
import { usePathname } from "next/navigation";
import Navbar from "./Navbar";
export default function ClientLayout({ children }: { children: React.ReactNode }) {
const pathname = usePathname();
const isAdmin = pathname?.startsWith("/admin");
return (
<>
{!isAdmin && <Navbar />}
{children}
</>
);
}

232
components/Contact.tsx Normal file
View File

@@ -0,0 +1,232 @@
"use client";
import { useState, useEffect } from "react";
import { MapPin, Mail, Send, ChevronDown, Instagram, Twitter, Linkedin, CheckCircle2, AlertCircle } from "lucide-react";
import { getSettings, submitLead } from "@/app/actions";
export default function Contact() {
const [formData, setFormData] = useState({
firstName: "",
lastName: "",
email: "",
projectType: "Drone Çekimi",
message: ""
});
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
const [settings, setSettings] = useState<any>(null);
useEffect(() => {
async function fetchSettings() {
const data = await getSettings();
if (data) setSettings(data);
}
fetchSettings();
}, []);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setStatus('loading');
try {
const result = await submitLead(formData);
if (result.error) throw new Error(result.error);
setStatus('success');
setFormData({ firstName: "", lastName: "", email: "", projectType: "Drone Çekimi", message: "" });
} catch (error) {
console.error('Error submitting form:', error);
setStatus('error');
}
};
return (
<section className="min-h-screen py-24 px-6 md:px-12 bg-[#f5f5f0]">
<div className="max-w-7xl mx-auto">
{/* Header Area */}
<div className="mb-20">
<span className="text-[10px] tracking-[0.2em] uppercase text-black/40 block mb-6">İletişim</span>
<h1 className="editorial-headline text-4xl md:text-6xl text-black reveal opacity-0 uppercase">
Markanızı Dijitalde <br /> <span className="text-primary">Büyütelim.</span>
</h1>
</div>
<div className="grid grid-cols-1 lg:grid-cols-12 gap-16 items-start border-t border-black/10 pt-16">
{/* Left Side - Info */}
<div className="lg:col-span-5 space-y-16">
<div className="space-y-6">
<p className="text-black/60 text-[14px] leading-relaxed max-w-sm">
{settings?.site_description || "Dijital dünyada fark yaratmaya hazır mısınız? Sosyal medya yönetimi, reklam stratejileri veya SEO çözümleri için vizyonunuzu hayata geçirelim."}
</p>
</div>
{/* Contact Channels */}
<div className="space-y-10">
<div className="flex items-start gap-4">
<div className="w-10 h-10 border border-black/10 flex items-center justify-center text-primary shrink-0">
<MapPin className="w-5 h-5" />
</div>
<div>
<h3 className="text-[10px] tracking-[0.2em] uppercase text-black/40 mb-2">Konum</h3>
<p className="text-[13px] text-black font-medium leading-relaxed">
{settings?.office_address || "Muğla / Marmaris\nDijital Medya Merkezi"}
</p>
</div>
</div>
<div className="flex items-start gap-4">
<div className="w-10 h-10 border border-black/10 flex items-center justify-center text-primary shrink-0">
<Mail className="w-5 h-5" />
</div>
<div>
<h3 className="text-[10px] tracking-[0.2em] uppercase text-black/40 mb-2">E-Posta & Telefon</h3>
<p className="text-[13px] text-black font-medium hover:text-primary transition-colors cursor-pointer mb-1">
{settings?.contact_email || "hello@mugladijital.com"}
</p>
<p className="text-[13px] text-black font-medium">
{settings?.contact_phone || "+90 (555) 000 00 00"}
</p>
</div>
</div>
</div>
{/* Social Links */}
<div className="space-y-6">
<h3 className="text-[10px] tracking-[0.2em] uppercase text-black/40">Sosyal Medya</h3>
<div className="flex gap-4">
{[
{ icon: Instagram, label: "Instagram", href: settings?.instagram_url },
{ icon: Twitter, label: "Twitter", href: settings?.twitter_url },
{ icon: Linkedin, label: "LinkedIn", href: settings?.linkedin_url }
].map((social) => (
<a
key={social.label}
href={social.href || "#"}
target="_blank"
rel="noopener noreferrer"
className="w-10 h-10 border border-black/10 flex items-center justify-center text-black/40 hover:text-primary hover:border-primary/50 transition-all"
aria-label={social.label}
>
<social.icon className="w-4 h-4" />
</a>
))}
</div>
</div>
</div>
{/* Right Side - Form */}
<div className="lg:col-span-7">
<div className="border border-black/10 p-8 md:p-12 relative overflow-hidden bg-white/30 backdrop-blur-sm">
{status === 'success' ? (
<div className="flex flex-col items-center justify-center text-center py-12 space-y-6">
<div className="w-16 h-16 border border-primary/20 flex items-center justify-center text-primary">
<CheckCircle2 className="w-8 h-8" />
</div>
<h3 className="editorial-headline text-2xl text-black uppercase">Mesajınız Alındı!</h3>
<p className="text-black/40 text-[12px] max-w-sm">
Ekibimiz en kısa sürede sizinle iletişime geçecektir.
</p>
<button
onClick={() => setStatus('idle')}
className="button-secondary text-[11px]"
>
Yeni Mesaj Gönder
</button>
</div>
) : (
<form onSubmit={handleSubmit} className="space-y-10">
<div className="grid grid-cols-1 md:grid-cols-2 gap-10">
<div className="space-y-3">
<label className="text-[10px] tracking-[0.2em] uppercase text-black/40 ml-1">Adınız</label>
<input
required
type="text"
value={formData.firstName}
onChange={(e) => setFormData({ ...formData, firstName: e.target.value })}
placeholder="Adınız"
className="w-full bg-transparent border-b border-black/10 py-3 text-[13px] text-black placeholder:text-black/10 outline-none focus:border-primary transition-colors"
/>
</div>
<div className="space-y-3">
<label className="text-[10px] tracking-[0.2em] uppercase text-black/40 ml-1">Soyadınız</label>
<input
required
type="text"
value={formData.lastName}
onChange={(e) => setFormData({ ...formData, lastName: e.target.value })}
placeholder="Soyadınız"
className="w-full bg-transparent border-b border-black/10 py-3 text-[13px] text-black placeholder:text-black/10 outline-none focus:border-primary transition-colors"
/>
</div>
</div>
<div className="space-y-3">
<label className="text-[10px] tracking-[0.2em] uppercase text-black/40 ml-1">E-posta Adresiniz</label>
<input
required
type="email"
value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
placeholder="ornek@email.com"
className="w-full bg-transparent border-b border-black/10 py-3 text-[13px] text-black placeholder:text-black/10 outline-none focus:border-primary transition-colors"
/>
</div>
<div className="space-y-3 relative">
<label className="text-[10px] tracking-[0.2em] uppercase text-black/40 ml-1">Hizmet Türü</label>
<div className="relative">
<select
value={formData.projectType}
onChange={(e) => setFormData({ ...formData, projectType: e.target.value })}
className="w-full bg-transparent border-b border-black/10 py-3 text-[13px] text-black/60 appearance-none outline-none focus:border-primary transition-colors cursor-pointer"
>
<option>Drone Çekimi</option>
<option>Fotoğraf & Video Çekimi</option>
<option>Düğün / Nişan Çekimi</option>
<option>Sosyal Medya Yönetimi</option>
<option>Meta Reklam Yönetimi</option>
<option>Google Reklam Yönetimi</option>
<option>Web Site Tasarımı</option>
<option>SEO Optimizasyonu</option>
<option>Otel Tanıtım Çekimi</option>
</select>
<ChevronDown className="absolute right-0 top-1/2 -translate-y-1/2 w-4 h-4 text-black/20 pointer-events-none" />
</div>
</div>
<div className="space-y-3">
<label className="text-[10px] tracking-[0.2em] uppercase text-black/40 ml-1">Mesajınız</label>
<textarea
required
rows={4}
value={formData.message}
onChange={(e) => setFormData({ ...formData, message: e.target.value })}
placeholder="Projenizden bahsedin..."
className="w-full bg-transparent border-b border-black/10 py-3 text-[13px] text-black placeholder:text-black/10 outline-none focus:border-primary transition-colors resize-none"
/>
</div>
{status === 'error' && (
<div className="flex items-center gap-2 text-red-600 text-[11px] font-bold bg-red-50 p-4 border border-red-100">
<AlertCircle className="w-4 h-4" />
Bir hata oluştu. Lütfen tekrar deneyin.
</div>
)}
<button
disabled={status === 'loading'}
className="button-primary w-full justify-center group disabled:opacity-50"
>
{status === 'loading' ? 'Gönderiliyor...' : 'Ücretsiz Analiz Talebi Gönder'}
<Send className="w-3 h-3 group-hover:translate-x-1 group-hover:-translate-y-1 transition-transform" />
</button>
</form>
)}
</div>
</div>
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,39 @@
"use client";
interface DynamicLogoProps {
src: string;
color?: string;
width?: string;
height?: string;
size?: string;
className?: string;
}
export default function DynamicLogo({
src,
color = "currentColor",
width = "100%",
height = "40px",
size = "contain",
className = ""
}: DynamicLogoProps) {
return (
<div
className={className}
style={{
backgroundColor: color,
maskImage: `url(${src})`,
WebkitMaskImage: `url(${src})`,
maskRepeat: "no-repeat",
maskPosition: "center",
maskSize: size,
WebkitMaskRepeat: "no-repeat",
WebkitMaskPosition: "center",
WebkitMaskSize: size,
width: width,
height: height,
transition: "background-color 0.3s ease",
}}
/>
);
}

91
components/Footer.tsx Normal file
View File

@@ -0,0 +1,91 @@
"use client";
import { useEffect, useState } from "react";
import { getSettings } from "@/app/actions";
import Link from "next/link";
import DynamicLogo from "./DynamicLogo";
export default function Footer() {
const [settings, setSettings] = useState<any>(null);
useEffect(() => {
async function fetchSettings() {
const data = await getSettings();
if (data) setSettings(data);
}
fetchSettings();
}, []);
return (
<footer className="border-t border-black/10">
{/* Main Footer Content */}
<div className="max-w-7xl mx-auto px-6 md:px-12 py-16 md:py-20">
<div className="grid grid-cols-1 md:grid-cols-12 gap-12 md:gap-8">
{/* Left Column - Logo & Description */}
<div className="md:col-span-5 flex flex-col justify-between gap-12">
{/* Logo */}
<Link href="/" className="inline-block">
<div className="relative w-40 h-12">
<DynamicLogo
src="/logo.png"
color="black"
width="100%"
height="100%"
size="contain"
/>
</div>
</Link>
{/* Description */}
<p className="text-[11px] text-black/40 leading-[1.8] max-w-xs">
{settings?.footer_description || "Muğla Dijital olarak markaların dijital dünyada özgün bir şekilde var olmasını sağlıyoruz. Drone çekimi, video prodüksiyon ve sosyal medya yönetimi ile gerçek bağlantılar kuruyoruz."}
</p>
</div>
{/* Center Column - Menu label + divider */}
<div className="md:col-span-2 flex flex-col items-center gap-6 hidden md:flex">
<div className="flex flex-col items-center gap-4">
<div className="w-px h-8 bg-black/10" />
<span className="text-[10px] tracking-[0.2em] uppercase text-black/30">Menu</span>
</div>
</div>
{/* Right Column - Navigation Links */}
<div className="md:col-span-5 flex flex-col items-start md:items-end gap-3">
{[
{ label: "Çalışmalar", href: "/works" },
{ label: "Hizmetler", href: "/services" },
{ label: "Partnerler", href: "/partners" },
{ label: "Hakkımızda", href: "/about" },
{ label: "İletişim", href: "/contact" },
].map((item) => (
<Link
key={item.label}
href={item.href}
className="text-2xl md:text-4xl font-extrabold uppercase tracking-tight text-black hover:text-primary transition-colors leading-tight"
>
{item.label}
</Link>
))}
</div>
</div>
</div>
{/* Bottom Bar */}
<div className="border-t border-black/10">
<div className="max-w-7xl mx-auto px-6 md:px-12 py-6 flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
{/* Copyright */}
<p className="text-[10px] text-black/25 tracking-[0.05em]">
© {settings?.site_name || "Muğla Dijital"} {new Date().getFullYear()}. Dijital çözümler üreten ajans.
</p>
{/* Credit */}
<a href="https://ayris.tech" target="_blank" rel="noopener noreferrer" className="text-[10px] text-black/25 tracking-[0.05em] hover:text-primary transition-colors">
created by ayris.tech
</a>
</div>
</div>
</footer>
);
}

64
components/Hero.tsx Normal file
View File

@@ -0,0 +1,64 @@
"use client";
import Link from "next/link";
import { ArrowRight } from "lucide-react";
import { motion } from "framer-motion";
export default function Hero() {
return (
<section className="pt-32 pb-0 px-6 md:px-12">
{/* Main Headline */}
<div className="max-w-7xl mx-auto py-16 md:py-24">
<motion.h1
initial={{ y: 40, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ duration: 1, ease: [0.16, 1, 0.3, 1] }}
className="editorial-headline text-4xl md:text-6xl lg:text-[5.5rem] text-black uppercase"
>
Dijital Varlık ve Görsel<br />
Hikaye <span className="text-primary">Mimarlığı.</span>
</motion.h1>
<motion.p
initial={{ y: 20, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ duration: 1, delay: 0.3, ease: [0.16, 1, 0.3, 1] }}
className="text-[11px] md:text-[13px] tracking-[0.15em] text-black/40 max-w-2xl leading-[2] mt-8"
>
Profesyonel prodüksiyondan akıllı reklam yönetimine kadar markanızın tüm dijital ekosistemini estetikle şekillendiriyoruz.
</motion.p>
</div>
{/* Divider */}
<motion.div
initial={{ scaleX: 0 }}
animate={{ scaleX: 1 }}
transition={{ duration: 1.5, delay: 0.5, ease: [0.16, 1, 0.3, 1] }}
className="section-divider origin-left"
/>
{/* Bottom info row */}
<motion.div
initial={{ y: 20, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ duration: 1, delay: 0.8, ease: [0.16, 1, 0.3, 1] }}
className="max-w-7xl mx-auto grid grid-cols-1 md:grid-cols-3 py-8 gap-8"
>
<div className="flex items-center gap-4">
<span className="text-[10px] tracking-[0.2em] uppercase text-black/40">Konum</span>
<span className="text-[11px] text-black/70">Muğla, Türkiye</span>
</div>
<div className="flex items-center gap-4">
<span className="text-[10px] tracking-[0.2em] uppercase text-black/40">Hizmetler</span>
<span className="text-[11px] text-black/70">Drone · Video · Sosyal Medya · Reklam</span>
</div>
<div className="flex items-center gap-4 md:justify-end">
<Link href="/contact" className="button-primary group">
Teklif Al
<ArrowRight className="w-3 h-3 group-hover:translate-x-1 transition-transform" />
</Link>
</div>
</motion.div>
</section>
);
}

83
components/Navbar.tsx Normal file
View File

@@ -0,0 +1,83 @@
"use client";
import Link from "next/link";
import DynamicLogo from "./DynamicLogo";
import { motion } from "framer-motion";
export default function Navbar() {
return (
<motion.nav
initial={{ y: -100 }}
animate={{ y: 0 }}
transition={{ duration: 1, ease: [0.16, 1, 0.3, 1] }}
className="fixed top-0 left-0 w-full z-50 bg-[#f5f5f0]/90 backdrop-blur-md border-b border-black/10"
>
<div className="flex items-center justify-between px-6 md:px-12 py-5">
{/* Logo */}
<Link href="/" className="flex items-center gap-3">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.5 }}
className="relative w-36 h-10"
>
<DynamicLogo
src="/logo.png"
color="black"
width="100%"
height="100%"
size="contain"
/>
</motion.div>
</Link>
{/* Center Nav */}
<div className="hidden lg:flex items-center">
{[
{ label: "Çalışmalar", href: "/works" },
{ label: "Hizmetler", href: "/services" },
{ label: "Partnerler", href: "/partners" },
{ label: "Hakkımızda", href: "/about" },
{ label: "İletişim", href: "/contact" },
].map((item, idx) => (
<div key={item.label} className="flex items-center">
{/* Diagonal separator */}
<motion.div
initial={{ opacity: 0, scaleY: 0 }}
animate={{ opacity: 1, scaleY: 1 }}
transition={{ delay: 0.2 + idx * 0.1 }}
className="w-16 h-10 relative mx-1"
>
<div className="absolute inset-0 flex items-center justify-center">
<div className="w-px h-14 bg-black/10 rotate-[-25deg]" />
</div>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3 + idx * 0.1 }}
>
<Link
href={item.href}
className="text-[11px] tracking-[0.15em] uppercase text-black/60 hover:text-black transition-colors nav-link-hover px-3 py-2"
>
{item.label}
</Link>
</motion.div>
</div>
))}
</div>
{/* Right - Brand name */}
<motion.span
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 1 }}
className="text-[13px] font-bold tracking-[0.1em] uppercase text-black"
>
Muğla Dijital
</motion.span>
</div>
</motion.nav>
);
}

120
components/Partners.tsx Normal file
View File

@@ -0,0 +1,120 @@
"use client";
import { useEffect, useState } from "react";
import { getPartners } from "@/app/actions";
import { motion } from "framer-motion";
import DynamicLogo from "./DynamicLogo";
import Link from "next/link";
export default function Partners() {
const [partners, setPartners] = useState<any[]>([]);
useEffect(() => {
async function fetchPartners() {
const data = await getPartners();
setPartners(data || []);
}
fetchPartners();
}, []);
if (partners.length === 0) return null;
return (
<section className="border-y border-black/10 bg-[#f5f5f0] overflow-hidden">
<div className="max-w-7xl mx-auto px-6 md:px-12 flex items-stretch min-h-[100px] md:min-h-[140px]">
{/* Left Label Section */}
<motion.div
initial={{ x: -20, opacity: 0 }}
whileInView={{ x: 0, opacity: 1 }}
viewport={{ once: true }}
className="flex items-center gap-4 py-6 md:py-8 pr-8 border-r border-black/10 shrink-0"
>
<span className="text-[9px] md:text-[10px] tracking-[0.2em] uppercase text-black/30 font-bold">Partners</span>
</motion.div>
{/* Partners List Section */}
<div className="flex-1 flex items-center pl-4 md:pl-8 pr-4 md:pr-8 overflow-hidden">
<div className="flex flex-nowrap items-center justify-start w-full gap-4 md:gap-10">
{partners.slice(0, 5).map((partner, index) => {
const content = (
<motion.div
initial={{ y: 10, opacity: 0 }}
whileInView={{ y: 0, opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: index * 0.1 + 0.5 }}
className="relative flex items-center justify-center group"
>
{partner.logo ? (
<div className="relative h-[60px] md:h-[75px] w-[90px] md:w-[130px] overflow-hidden">
<motion.div
whileHover={{ y: "-50%" }}
transition={{ duration: 0.4, ease: [0.16, 1, 0.3, 1] }}
className="flex flex-col items-center h-[200%]"
>
{/* Normal State */}
<div className="h-1/2 w-full flex items-center justify-center opacity-70">
<DynamicLogo
src={partner.logo}
color="black"
width="100%"
height="100%"
size="220%"
/>
</div>
{/* Hover State */}
<div className="h-1/2 w-full flex items-center justify-center">
<DynamicLogo
src={partner.logo}
color="#ff5c00" // primary color
width="100%"
height="100%"
size="220%"
/>
</div>
</motion.div>
</div>
) : (
<span className="text-[14px] md:text-[18px] tracking-tight font-medium text-black/30 whitespace-nowrap">
{partner.name}
</span>
)}
</motion.div>
);
if (partner.project_slug) {
return (
<Link key={index} href={`/works/${partner.project_slug}`}>
{content}
</Link>
);
}
return <div key={index}>{content}</div>;
})}
</div>
</div>
{/* Right CTA Section */}
<motion.div
initial={{ x: 20, opacity: 0 }}
whileInView={{ x: 0, opacity: 1 }}
viewport={{ once: true }}
className="flex items-center py-6 md:py-8 pl-8 border-l border-black/10 shrink-0"
>
<a
href="/partners"
className="text-[10px] md:text-[11px] tracking-[0.1em] font-bold uppercase text-black hover:text-primary transition-colors flex items-center gap-2 group"
>
Hepsini Gör
<motion.span
animate={{ x: [0, 5, 0] }}
transition={{ repeat: Infinity, duration: 2 }}
>
</motion.span>
</a>
</motion.div>
</div>
</section>
);
}

View File

@@ -0,0 +1,92 @@
"use client";
import { motion } from "framer-motion";
import DynamicLogo from "./DynamicLogo";
import Link from "next/link";
interface Partner {
id: number;
name: string;
logo?: string;
url?: string;
project_slug?: string;
}
export default function PartnersList({ partners }: { partners: Partner[] }) {
return (
<section className="py-24 px-6 md:px-12">
<div className="max-w-7xl mx-auto">
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 border-t border-l border-black/10">
{partners.map((partner, index) => {
const card = (
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: index * 0.05 }}
className="p-4 md:p-8 border-r border-b border-black/10 flex items-center justify-center transition-all group relative bg-white/10 overflow-hidden cursor-pointer"
>
<div className="relative h-[140px] md:h-[180px] w-full overflow-hidden">
<motion.div
whileHover={{ y: "-50%" }}
transition={{ duration: 0.4, ease: [0.16, 1, 0.3, 1] }}
className="flex flex-col items-center h-[200%]"
>
{/* First state */}
<div className="h-1/2 w-full flex items-center justify-center opacity-70 group-hover:opacity-100 transition-all">
{partner.logo ? (
<DynamicLogo
src={partner.logo}
color="black"
width="100%"
height="100%"
size="140%"
/>
) : (
<span className="editorial-headline text-xl md:text-2xl text-black uppercase">
{partner.name}
</span>
)}
</div>
{/* Second state (Slot effect) */}
<div className="h-1/2 w-full flex items-center justify-center">
{partner.logo ? (
<DynamicLogo
src={partner.logo}
color="#ff5c00" // primary color
width="100%"
height="100%"
size="140%"
/>
) : (
<span className="editorial-headline text-xl md:text-2xl text-primary uppercase">
{partner.name}
</span>
)}
</div>
</motion.div>
</div>
{/* Subtle diagonal hover effect */}
<div className="absolute top-0 right-0 w-8 h-8 opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none">
<div className="absolute top-0 right-0 w-px h-12 bg-black/5 rotate-[-45deg] origin-top-right" />
</div>
</motion.div>
);
if (partner.project_slug) {
return (
<Link key={partner.id} href={`/works/${partner.project_slug}`} className="block">
{card}
</Link>
);
}
return <div key={partner.id}>{card}</div>;
})}
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,108 @@
"use client";
import { useEffect, useState } from "react";
import Image from "next/image";
import Link from "next/link";
import { ArrowRight, Loader2 } from "lucide-react";
import { getFeaturedProjects } from "@/app/actions";
interface ProjectCardProps {
hero_image: string;
category: string;
title: string;
year: string;
subtitle: string;
slug: string;
}
function ProjectCard({ hero_image, category, title, year, subtitle, slug }: ProjectCardProps) {
return (
<Link href={`/works/${slug}`} className="group cursor-pointer block">
<div className="space-y-5">
<div className="relative aspect-video overflow-hidden bg-black/5 border border-black/10">
<Image
src={hero_image || "https://images.unsplash.com/photo-1550745165-9bc0b252726f"}
alt={title}
fill
className="object-cover transition-all duration-700 group-hover:scale-105 grayscale group-hover:grayscale-0"
/>
{/* Category Badge */}
<div className="absolute top-4 right-4">
<span className="bg-white/90 backdrop-blur-sm border border-black/10 px-3 py-1 text-[9px] tracking-[0.15em] uppercase text-black/60">
{category}
</span>
</div>
</div>
{/* Content Below Image */}
<div>
<div className="flex justify-between items-start mb-2">
<h3 className="text-[14px] tracking-[0.05em] uppercase text-black group-hover:text-primary transition-colors leading-tight">
{title}
</h3>
<span className="text-[10px] text-black/30 tracking-[0.1em] uppercase mt-0.5">
{year}
</span>
</div>
<p className="text-[11px] text-black/40 leading-relaxed line-clamp-1">
{subtitle}
</p>
</div>
</div>
</Link>
);
}
export default function SelectedWorks() {
const [projects, setProjects] = useState<any[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchFeatured() {
setLoading(true);
const data = await getFeaturedProjects();
if (data && data.length > 0) {
setProjects(data);
}
setLoading(false);
}
fetchFeatured();
}, []);
if (loading) return (
<div className="py-32 flex justify-center">
<Loader2 className="w-8 h-8 text-primary animate-spin" />
</div>
);
if (projects.length === 0) return null;
return (
<section className="py-24 px-6 md:px-12 border-t border-black/10">
<div className="max-w-7xl mx-auto">
{/* Header Section */}
<div className="flex flex-col md:flex-row justify-between items-start md:items-end gap-8 mb-16">
<div>
<span className="text-[10px] tracking-[0.2em] uppercase text-black/40 block mb-4">Son Projeler</span>
<h2 className="editorial-headline text-4xl md:text-5xl text-black">
Çalışma Örnekleri
</h2>
</div>
<Link href="/works" className="button-primary group">
Tüm Portfolyo
<ArrowRight className="w-3 h-3 group-hover:translate-x-1 transition-transform" />
</Link>
</div>
{/* Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-10">
{projects.map((project, index) => (
<ProjectCard key={index} {...project} />
))}
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,128 @@
"use client";
import { useState } from "react";
import Image from "next/image";
import Link from "next/link";
import * as LucideIcons from "lucide-react";
import {
ArrowRight,
Layers,
Search,
Clapperboard,
Camera,
Zap
} from "lucide-react";
import Footer from "@/components/Footer";
const processSteps = [
{ icon: Search, title: "Analiz", desc: "İşletmenizi ve hedef kitlenizi analiz ediyoruz." },
{ icon: Clapperboard, title: "Strateji", desc: "Size özel dijital strateji planlıyoruz." },
{ icon: Camera, title: "Uygulama", desc: "Çekim, tasarım ve kampanya yönetimi." },
{ icon: Zap, title: "Raporlama", desc: "Sonuçları ölçüyor ve optimize ediyoruz." }
];
export default function ServicesClient({ services: initialServices }: { services: any[] }) {
const [services] = useState<any[]>(initialServices);
const DynamicIcon = ({ name, className }: { name: string, className?: string }) => {
const IconComponent = (LucideIcons as any)[name] || Layers;
return <IconComponent className={className} />;
};
return (
<main className="min-h-screen bg-[#f5f5f0] text-black pt-24">
{/* Hero Section */}
<section className="pt-24 pb-16 px-6 md:px-12 border-b border-black/10">
<div className="max-w-7xl mx-auto">
<span className="text-[10px] tracking-[0.2em] uppercase text-black/40 block mb-6">Hizmetlerimiz</span>
<h1 className="editorial-headline text-4xl md:text-6xl lg:text-[5.5rem] text-black reveal opacity-0 uppercase">
Drone · Video <br /> <span className="text-primary">Reklam · Dijital</span>
</h1>
<p className="text-black/40 text-[14px] max-w-2xl leading-relaxed mt-10 reveal reveal-delayed-1 opacity-0">
Profesyonel drone çekimlerinden sosyal medya yönetimine, Google reklamlarından web tasarıma işletmenizin dijital dünyada parlaması için ihtiyacınız olan her şey burada.
</p>
</div>
</section>
{/* Services Grid - Editorial Bento */}
<section className="py-24 px-6 md:px-12 border-b border-black/10">
<div className="max-w-7xl mx-auto">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 border-t border-l border-black/10">
{services.map((item) => (
<div key={item.id} className="p-10 border-r border-b border-black/10 relative group hover:bg-black/[0.01] transition-colors overflow-hidden flex flex-col justify-between min-h-[350px]">
<div>
<div className="w-10 h-10 border border-black/10 flex items-center justify-center text-primary mb-8">
<DynamicIcon name={item.icon_name} className="w-5 h-5" />
</div>
<h3 className="editorial-headline text-2xl text-black mb-4 uppercase">{item.title}</h3>
<p className="text-[12px] text-black/40 leading-relaxed font-medium mb-8">
{item.description}
</p>
</div>
<ul className="space-y-3">
{(item.sub_services || []).slice(0, 3).map((sub: string) => (
<li key={sub} className="flex items-center gap-3 text-[9px] font-bold tracking-widest text-black/20 uppercase">
<div className="w-1 h-1 rounded-full bg-primary" />
{sub}
</li>
))}
</ul>
{/* Subtle diagonal on hover */}
<div className="absolute top-0 right-0 w-16 h-16 opacity-0 group-hover:opacity-100 transition-opacity">
<div className="absolute top-0 right-0 w-px h-24 bg-black/5 rotate-[-45deg] origin-top-right" />
</div>
</div>
))}
</div>
</div>
</section>
{/* The Process - Editorial Layout */}
<section className="py-24 px-6 md:px-12 border-b border-black/10">
<div className="max-w-7xl mx-auto">
<div className="mb-20">
<span className="text-[10px] tracking-[0.2em] uppercase text-black/40 block mb-4">İş Akışımız</span>
<h2 className="editorial-headline text-3xl md:text-5xl text-black uppercase">Süreç Nasıl İlerler?</h2>
</div>
<div className="grid grid-cols-1 md:grid-cols-4 border-t border-black/10">
{processSteps.map((step, idx) => (
<div key={step.title} className="py-12 md:px-8 border-b md:border-b-0 md:border-r border-black/10 last:border-r-0 group">
<div className="text-4xl font-black text-black/5 mb-8 group-hover:text-primary/20 transition-colors">0{idx + 1}</div>
<div className="w-8 h-8 border border-black/10 flex items-center justify-center text-primary mb-6">
<step.icon className="w-4 h-4" />
</div>
<h3 className="editorial-headline text-lg text-black mb-4 uppercase">{step.title}</h3>
<p className="text-[12px] text-black/40 leading-relaxed">{step.desc}</p>
</div>
))}
</div>
</div>
</section>
{/* CTA Section */}
<section className="py-24 px-6 text-center">
<div className="max-w-4xl mx-auto space-y-12">
<h2 className="editorial-headline text-4xl md:text-6xl text-black uppercase leading-tight">
Sıradışı Bir Şeyler <br /> <span className="text-primary">Yaratmaya Hazır Mısınız?</span>
</h2>
<p className="text-black/40 text-[13px] tracking-[0.1em] max-w-xl mx-auto">
Drone çekimi, sosyal medya yönetimi veya dijital reklam ne ihtiyacınız varsa, birlikte çözüm üretelim.
</p>
<div className="flex flex-col sm:flex-row items-center justify-center gap-6">
<Link href="/contact" className="button-primary px-10">
Hemen Başlayalım
</Link>
<Link href="/works" className="button-secondary px-10">
Portfolyomuz
</Link>
</div>
</div>
</section>
<Footer />
</main>
);
}

143
components/ServicesGrid.tsx Normal file
View File

@@ -0,0 +1,143 @@
"use client";
import { useEffect, useState } from "react";
import { getFeaturedServices } from "@/app/actions";
import Image from "next/image";
import Link from "next/link";
import { motion } from "framer-motion";
export default function ServicesGrid() {
const [services, setServices] = useState<any[]>([]);
useEffect(() => {
async function fetchServices() {
const data = await getFeaturedServices();
if (data && data.length > 0) setServices(data);
}
fetchServices();
}, []);
return (
<section className="border-t border-black/10">
<div className="max-w-7xl mx-auto px-6 md:px-12">
{/* Grid - Editorial bento layout */}
<div className="grid grid-cols-1 md:grid-cols-12 border-b border-black/10">
{/* Left large cell with image */}
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ duration: 1 }}
className="md:col-span-4 border-b md:border-b-0 md:border-r border-black/10 relative overflow-hidden group"
>
<div className="relative aspect-square md:aspect-auto md:h-full min-h-[400px]">
<Image
src="https://images.unsplash.com/photo-1473968512647-3e447244af8f?q=80&w=800"
alt="Drone çekimi"
fill
className="object-cover grayscale group-hover:grayscale-0 transition-all duration-700 group-hover:scale-105"
/>
</div>
</motion.div>
{/* Right content area */}
<div className="md:col-span-8 grid grid-cols-1 md:grid-cols-2">
{/* Top-left cell: Services list */}
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: 0.2 }}
className="p-8 md:p-12 border-b border-r border-black/10 flex flex-col justify-between min-h-[200px]"
>
<div>
<span className="text-[10px] tracking-[0.2em] uppercase text-black/40 block mb-6">Hizmetler</span>
<div className="space-y-2">
{["Sosyal Medya Yönetimi", "Drone Çekimi", "Video Prodüksiyon", "Reklam Yönetimi", "SEO"].map((item) => (
<div key={item} className="text-[12px] text-black/60 hover:text-primary transition-colors cursor-pointer">
{item}
</div>
))}
</div>
</div>
</motion.div>
{/* Top-right cell: Capabilities */}
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: 0.4 }}
className="p-8 md:p-12 border-b border-black/10 flex flex-col justify-between min-h-[200px]"
>
<div>
<span className="text-[10px] tracking-[0.2em] uppercase text-black/40 block mb-6">Çözümler</span>
<div className="space-y-2">
{["Fotoğraf Çekimi", "Web Tasarım", "Otel Tanıtım", "Düğün Çekimi", "İçerik Üretimi"].map((item) => (
<div key={item} className="text-[12px] text-black/60 hover:text-primary transition-colors cursor-pointer">
{item}
</div>
))}
</div>
</div>
</motion.div>
{/* Bottom-left cell with diagonal */}
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: 0.6 }}
className="p-8 md:p-12 border-r border-black/10 relative cell-diagonal min-h-[200px] flex items-end"
>
<h3 className="editorial-headline text-2xl md:text-3xl text-black uppercase">
Profesyonel<br />
Prodüksiyon
</h3>
</motion.div>
{/* Bottom-right cell */}
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: 0.8 }}
className="p-8 md:p-12 relative cell-diagonal min-h-[200px] flex items-end"
>
<h3 className="editorial-headline text-2xl md:text-3xl text-black uppercase">
Dijital<br />
Pazarlama
</h3>
</motion.div>
</div>
</div>
{/* Description row */}
<div className="py-8 grid grid-cols-1 md:grid-cols-12 gap-8">
<motion.div
initial={{ opacity: 0, x: -20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
className="md:col-span-4 flex items-center"
>
<p className="text-[12px] text-black/50 leading-relaxed">
Drone çekimlerinden sosyal medya yönetimine, markanızın dijitaldeki her ihtiyacını karşılıyoruz.
</p>
</motion.div>
<motion.div
initial={{ opacity: 0, x: 20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
className="md:col-span-4 md:col-start-9 flex items-center md:justify-end"
>
<Link href="/services" className="button-primary group">
Tüm Hizmetler
<span className="group-hover:translate-x-1 transition-transform"></span>
</Link>
</motion.div>
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,193 @@
"use client";
import Image from "next/image";
import Link from "next/link";
import { ArrowRight, Share2 } from "lucide-react";
import Footer from "@/components/Footer";
export default function WorkDetailClient({ project, nextProject }: { project: any, nextProject: any }) {
const isInstagram = (url: string) => {
return url.includes('instagram.com');
};
const isVideo = (url: string) => {
return url.includes('youtube.com') || url.includes('vimeo.com') || url.endsWith('.mp4');
};
// Ultra-safety check for gallery and category arrays
const parseSafe = (data: any) => {
let current = data;
try {
// Aggressively parse up to 3 times to handle double-quotes and double-encoding
for (let i = 0; i < 3; i++) {
if (typeof current === 'string' && (current.trim().startsWith('[') || current.trim().startsWith('"'))) {
current = JSON.parse(current);
} else {
break;
}
}
return Array.isArray(current) ? current : (typeof current === 'string' && current ? [current] : []);
} catch (e) {
return Array.isArray(current) ? current : (typeof current === 'string' && current ? [current] : []);
}
};
const gallery = parseSafe(project.gallery);
const categories = parseSafe(project.category);
// Helper to get Instagram embed URL
const getInstaEmbedUrl = (url: string) => {
const cleanUrl = url.split('?')[0];
return `${cleanUrl}${cleanUrl.endsWith('/') ? '' : '/'}embed`;
};
return (
<main className="min-h-screen bg-[#f5f5f0] text-black pt-24">
{/* 1. Editorial Header Section */}
<section className="pt-32 pb-20 px-6 md:px-12 border-b border-black/10">
<div className="max-w-7xl mx-auto">
{/* Top Line */}
<div className="w-full h-px bg-black/10 mb-20" />
<div className="grid grid-cols-1 lg:grid-cols-12 gap-16 items-start">
{/* Left: Client Name */}
<div className="lg:col-span-5">
<span className="text-[10px] tracking-[0.3em] uppercase text-black/30 block mb-6">
{categories.join(" / ")} / {project.year}
</span>
<h1 className="editorial-headline text-5xl md:text-7xl lg:text-8xl text-black uppercase leading-none">
{project.client || project.title}
</h1>
</div>
{/* Middle: Minimalist Line (Reference style) */}
<div className="hidden lg:block lg:col-span-2 pt-12">
<div className="w-20 h-px bg-black/40 mx-auto" />
</div>
{/* Right: Description */}
<div className="lg:col-span-5 pt-2 lg:pt-8">
<p className="text-[15px] md:text-[18px] text-black/70 leading-[1.8] font-medium italic">
{project.narrative_desc || project.subtitle}
</p>
<div className="mt-12 flex flex-wrap gap-x-8 gap-y-4">
<div>
<h4 className="text-[9px] tracking-[0.2em] uppercase text-black/30 mb-1">Rol</h4>
<span className="text-[11px] font-bold uppercase">{project.role || "Kreatif Direktörlük"}</span>
</div>
<div>
<h4 className="text-[9px] tracking-[0.2em] uppercase text-black/30 mb-1">Konum</h4>
<span className="text-[11px] font-bold uppercase">{project.location || "Muğla / Dijital"}</span>
</div>
</div>
</div>
</div>
{/* Bottom Line */}
<div className="w-full h-px bg-black/10 mt-20" />
</div>
</section>
{/* 2. Project Feed (Gallery & Instagram) */}
<section className="py-24 px-6 md:px-12">
<div className="max-w-4xl mx-auto space-y-32">
{/* Hero Image First */}
<div className="relative aspect-[16/10] w-full overflow-hidden border border-black/5 shadow-2xl bg-[#e2d1c1] p-1">
<div className="relative w-full h-full overflow-hidden">
<Image
src={project.hero_image || "https://images.unsplash.com/photo-1550745165-9bc0b252726f"}
alt={project.title}
fill
className="object-cover"
priority
/>
</div>
</div>
{/* Gallery / Instagram Feed */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-12 gap-y-24 mt-24">
{gallery.map((item: string, idx: number) => (
<div key={idx} className="space-y-8 animate-reveal">
<div className="flex items-center gap-4 text-[10px] font-bold text-black/20 tracking-widest uppercase">
<span>0{idx + 1}</span>
<div className="h-px flex-grow bg-black/5" />
<span>{isInstagram(item) ? "INSTAGRAM FEED" : "PRODUCTION VIEW"}</span>
</div>
{isInstagram(item) ? (
<div className="flex justify-center">
<div className="w-full max-w-[540px] border border-black/10 bg-white shadow-xl overflow-hidden rounded-xl">
<iframe
src={getInstaEmbedUrl(item)}
className="w-full h-[700px] border-0"
scrolling="no"
allowTransparency={true}
allowFullScreen
/>
</div>
</div>
) : (
<div className="relative aspect-[16/10] border border-black/5 bg-black/5 shadow-lg overflow-hidden group">
{isVideo(item) ? (
<iframe
src={item}
className="w-full h-full"
allowFullScreen
/>
) : (
<Image
src={item}
alt={`Gallery ${idx}`}
fill
className="object-cover transition-transform duration-1000 group-hover:scale-105"
/>
)}
</div>
)}
</div>
))}
</div>
</div>
</section>
{/* Minimal CTA Section */}
<section className="py-32 px-6 md:px-12 bg-[#f5f5f0]">
<div className="max-w-7xl mx-auto text-center">
<div className="w-full h-px bg-black/10 mb-24" />
<h2 className="editorial-headline text-3xl md:text-5xl lg:text-6xl text-black uppercase leading-tight mb-16 max-w-4xl mx-auto">
CESUR, İNSANCIL VE <br /> İZ BIRAKAN PROJELERİ <br /> <span className="text-primary">BİRLİKTE</span> ŞEKİLLENDİRELİM.
</h2>
<Link
href="/contact"
className="inline-flex items-center justify-center w-32 h-32 md:w-40 md:h-40 rounded-full bg-primary text-white text-[10px] font-bold uppercase tracking-widest hover:scale-110 transition-all duration-500 shadow-xl shadow-primary/20 group"
>
<span className="group-hover:scale-110 transition-transform">İLETİŞİME GEÇ</span>
</Link>
</div>
</section>
{/* Next Project - Editorial Style */}
{nextProject && (
<section className="relative border-y border-black/10 group overflow-hidden bg-[#f9f6ef] hover:bg-[#e2d1c1] transition-colors duration-700">
<Link href={`/works/${nextProject.slug}`} className="block py-40 px-6 md:px-12">
<div className="max-w-7xl mx-auto text-center space-y-12">
<span className="text-[10px] tracking-[0.5em] text-black/30 uppercase block">SIRADAKİ ÇALIŞMA</span>
<h2 className="editorial-headline text-5xl md:text-8xl lg:text-9xl text-black uppercase transition-all duration-700 group-hover:scale-[0.98]">
{nextProject.title}
</h2>
<div className="flex items-center justify-center gap-6 text-black/40 font-bold text-[12px] tracking-[0.3em] uppercase">
<div className="w-12 h-px bg-black/20" />
PROJEYİ GÖR
<div className="w-12 h-px bg-black/20" />
</div>
</div>
</Link>
</section>
)}
<Footer />
</main>
);
}

187
components/WorksClient.tsx Normal file
View File

@@ -0,0 +1,187 @@
"use client";
import Image from "next/image";
import { useState } from "react";
import Link from "next/link";
import { ArrowUpRight } from "lucide-react";
import Footer from "@/components/Footer";
interface ProjectCardProps {
hero_image: string;
category: string;
title: string;
year: string;
client: string;
slug: string;
narrative_desc: string;
index: number;
}
function ProjectCard({ hero_image, category, title, year, client, slug, narrative_desc, index }: ProjectCardProps) {
// Alternating background colors like in the reference screenshot
const bgColors = ["bg-[#e2d1c1]", "bg-[#f9f6ef]", "bg-[#d8c7b8]", "bg-[#f5f1e8]"];
const bgColor = bgColors[index % bgColors.length];
return (
<Link href={`/works/${slug}`} className="group cursor-pointer block h-full">
<div className={`p-8 md:p-10 h-full flex flex-col transition-all duration-500 group-hover:translate-y-[-8px] ${bgColor}`}>
{/* 1. Image Area */}
<div className="relative aspect-[16/10] overflow-hidden mb-12 shadow-sm">
<Image
src={hero_image || "https://images.unsplash.com/photo-1536440136628-849c177e76a1"}
alt={title}
fill
className="object-cover transition-transform duration-1000 group-hover:scale-105"
/>
{/* Floating Title on Image like reference */}
<div className="absolute inset-0 flex flex-col items-center justify-center text-center p-6 bg-black/10">
<span className="text-[10px] tracking-[0.2em] uppercase text-white/80 mb-2">
{(() => {
let current = category;
try {
for (let i = 0; i < 3; i++) {
if (typeof current === 'string' && (current.trim().startsWith('[') || current.trim().startsWith('"'))) {
current = JSON.parse(current);
} else {
break;
}
}
return Array.isArray(current) ? current.join(" / ") : current;
} catch (e) {
return current;
}
})()}
</span>
<h3 className="editorial-headline text-3xl md:text-4xl text-white uppercase leading-tight drop-shadow-md">
{title}
</h3>
</div>
</div>
{/* 2. Description Area */}
<div className="flex-grow mb-12">
<p className="text-black/70 text-[13px] leading-[1.8] line-clamp-6 font-medium italic">
{narrative_desc || "Dijital dünyada markanızın sesini duyurmak ve özgün bir kimlik kazandırmak için tasarladığımız özel projelerimizden biri."}
</p>
</div>
{/* 3. Footer / Client Area */}
<div className="border-t border-black/10 pt-8 mt-auto">
<div className="flex justify-between items-end">
<div>
<span className="text-[9px] tracking-[0.2em] uppercase text-black/30 block mb-2">Müşteri</span>
<h4 className="editorial-headline text-3xl text-black uppercase opacity-80 group-hover:opacity-100 group-hover:text-primary transition-all">
{client || "Muğla Dijital"}
</h4>
</div>
<div className="text-[10px] font-black text-black/20 group-hover:text-primary transition-colors border border-black/5 px-2 py-1 rounded">
{year}
</div>
</div>
</div>
</div>
</Link>
);
}
export default function WorksClient({ projects: initialProjects }: { projects: any[] }) {
const [activeCategory, setActiveCategory] = useState("Hepsi");
const categories = ["Hepsi", ...Array.from(new Set(initialProjects.flatMap(p => {
let current = p.category;
try {
for (let i = 0; i < 3; i++) {
if (typeof current === 'string' && (current.trim().startsWith('[') || current.trim().startsWith('"'))) {
current = JSON.parse(current);
} else {
break;
}
}
} catch (e) {}
return Array.isArray(current) ? current : (typeof current === 'string' && current ? [current] : []);
})))];
const filteredProjects = activeCategory === "Hepsi"
? initialProjects
: initialProjects.filter(p => {
let current = p.category;
try {
for (let i = 0; i < 3; i++) {
if (typeof current === 'string' && (current.trim().startsWith('[') || current.trim().startsWith('"'))) {
current = JSON.parse(current);
} else {
break;
}
}
} catch (e) {}
const cats = Array.isArray(current) ? current : (typeof current === 'string' && current ? [current] : []);
return cats.includes(activeCategory);
});
return (
<main className="min-h-screen bg-[#f5f5f0] text-black pt-24">
<section className="pt-24 pb-24 px-6 md:px-12">
<div className="max-w-7xl mx-auto">
{/* Header Area */}
<div className="mb-20">
<span className="text-[10px] tracking-[0.2em] uppercase text-black/40 block mb-6">Portfolyo</span>
<h1 className="editorial-headline text-4xl md:text-6xl lg:text-[5.5rem] text-black reveal opacity-0 uppercase">
Seçilmiş <br /> <span className="text-primary">Projeler.</span>
</h1>
<p className="text-black/40 text-[14px] max-w-2xl leading-relaxed mt-10 reveal reveal-delayed-1 opacity-0">
Markanızın dijital dünyadaki serüvenini profesyonel dokunuşlarla şekillendiriyoruz. Global vizyon, yerel strateji ile başarı hikayeleri yazıyoruz.
</p>
</div>
{/* Filter Section */}
<div className="flex flex-col md:flex-row justify-between items-center gap-8 mb-16 border-y border-black/10 py-8">
<div className="flex flex-wrap items-center gap-3">
{categories.map((cat) => (
<button
key={cat}
onClick={() => setActiveCategory(cat)}
className={`px-6 py-2 rounded-full text-[10px] font-bold uppercase tracking-widest transition-all border
${activeCategory === cat
? "bg-black text-white border-black"
: "text-black/40 border-black/10 hover:border-black/30 hover:text-black"
}`}
>
{cat}
</button>
))}
</div>
<div className="hidden md:block">
<span className="text-[10px] font-bold text-black/20 uppercase tracking-widest">
{filteredProjects.length} Proje
</span>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-8 gap-y-12">
{filteredProjects.map((project, index) => (
<ProjectCard key={index} {...project} index={index} />
))}
</div>
{filteredProjects.length === 0 && (
<div className="py-32 text-center border border-black/10">
<p className="text-black/40 text-sm">Bu kategoride henüz bir proje bulunmuyor.</p>
</div>
)}
{/* CTA Section Area */}
<div className="mt-32 border-t border-black/10 pt-24 text-center space-y-10">
<h2 className="editorial-headline text-3xl md:text-5xl text-black uppercase">Sıradaki Başarı Hikayesi <br /><span className="text-primary">Sizinle</span> Yazılsın.</h2>
<Link href="/contact" className="button-primary mx-auto">
Projeyi Başlat
<ArrowUpRight className="w-4 h-4" />
</Link>
</div>
</div>
</section>
<Footer />
</main>
);
}