feat: WP'den header + kart stilleri + blog sidebar widget

Header (components/header.tsx + header-scroll.tsx):
- WP'deki 'floating pill' efekti — scroll'da küçülen + yuvarlanan + gölgeli
- 3 sütun grid: Logo | Nav | CTA
- Hizmetler mega menu dropdown — 2 sütunlu (Web&Yazılım + Dijital Pazarlama)
  - Hover'da açılır, services tablosundan dinamik
  - Alt linkle 'Tüm hizmetleri gör'
- Mobil için scroll-down'da gizlenir
- Sağda 'Ücretsiz Teklif' CTA butonu + telefon link

Kart stilleri (WP'ye eşlendi):
- ServicesGrid:
  - Gradient icon (sky → purple) ile WP'deki '🎨 🚀 📱' emoji yerine ikon
  - Hover: -translate-y-2 + colored shadow + scale icon
  - ArrowUpRight ikonu absolute, hover'da görünür
- ProjectsGrid:
  - Kategori bazlı renkli badge (Kurumsal navy, Klinik cyan, Portfolio violet, …)
  - Hover: image scale-105 + gradient overlay
  - 5/3 aspect ratio (daha WP-like)

Public sidebar (components/content-sidebar.tsx):
- CTA card (gradient navy→sky): Telefon + WhatsApp
- Son yazılar (4 adet, kapak + başlık + tarih)
- Etiketler (en sık kullanılan 10)
- Hizmetler menü (6 adet)
- Site analizi lead magnet

Blog detay sayfası (/blog/[slug]):
- Tek sütun → 2 sütun grid (content + sidebar)
- sticky sidebar, max-w-7xl
- Aynı pattern hizmet/proje detay sayfalarına da uygulanabilir

37 route, build temiz.
This commit is contained in:
Ege Can Komur
2026-05-20 18:45:02 +03:00
parent deff889f0c
commit e45c44721f
6 changed files with 577 additions and 169 deletions
+82 -64
View File
@@ -3,6 +3,15 @@ import Link from "next/link";
import { ArrowUpRight, ExternalLink } from "lucide-react";
import type { ProjectRow } from "@/lib/types";
const CATEGORY_COLORS: Record<string, string> = {
"Kurumsal Web Sitesi": "bg-[var(--navy)]",
"Klinik Web Sitesi": "bg-cyan-600",
"Portfolyo & SEO": "bg-violet-600",
"Web Tasarım": "bg-emerald-600",
"Özel Yazılım": "bg-sky-600",
"E-Ticaret": "bg-pink-600",
};
export function ProjectsGrid({ projects }: { projects: ProjectRow[] }) {
if (projects.length === 0) {
return (
@@ -15,73 +24,82 @@ export function ProjectsGrid({ projects }: { projects: ProjectRow[] }) {
}
return (
<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
{projects.map((p) => (
<article
key={p.$id}
className="group overflow-hidden rounded-2xl border border-[var(--border)] bg-white transition hover:shadow-xl"
>
<Link href={`/projeler/${p.slug}`} className="block">
<div className="relative aspect-video overflow-hidden bg-[var(--navy-50)]">
{p.image_url ? (
<Image
src={p.image_url}
alt={p.title}
fill
sizes="(min-width: 1024px) 33vw, (min-width: 768px) 50vw, 100vw"
className="object-cover transition group-hover:scale-105"
/>
) : (
<div className="flex h-full items-center justify-center text-[var(--navy)]/30">
<span className="text-5xl font-bold">{p.title.charAt(0)}</span>
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
{projects.map((p) => {
const tagColor = p.category && CATEGORY_COLORS[p.category]
? CATEGORY_COLORS[p.category]
: "bg-[var(--navy)]";
return (
<article
key={p.$id}
className="group overflow-hidden rounded-2xl border border-[var(--border)] bg-white transition-all duration-300 hover:-translate-y-1 hover:shadow-2xl hover:shadow-[var(--navy)]/10"
>
<Link href={`/projeler/${p.slug}`} className="block">
<div className="relative aspect-[5/3] overflow-hidden bg-[var(--navy-50)]">
{p.image_url ? (
<Image
src={p.image_url}
alt={p.title}
fill
sizes="(min-width: 1024px) 33vw, (min-width: 768px) 50vw, 100vw"
className="object-cover transition-transform duration-500 group-hover:scale-105"
/>
) : (
<div className="flex h-full items-center justify-center text-[var(--navy)]/30">
<span className="text-5xl font-bold">{p.title.charAt(0)}</span>
</div>
)}
{/* Overlay gradient — WP stili */}
<div className="absolute inset-0 bg-gradient-to-t from-black/65 via-transparent to-transparent opacity-0 transition-opacity duration-300 group-hover:opacity-100" />
{p.category && (
<span
className={`absolute left-4 top-4 rounded-full ${tagColor} px-3 py-1 text-xs font-semibold text-white shadow-lg`}
>
{p.category}
</span>
)}
</div>
</Link>
<div className="p-6">
<div className="flex items-start justify-between gap-3">
<Link href={`/projeler/${p.slug}`} className="block">
<h3 className="text-lg font-bold text-[var(--navy)] transition-colors group-hover:text-[var(--sky-600)]">
{p.title}
</h3>
</Link>
{p.live_url ? (
<a
href={p.live_url}
target="_blank"
rel="noopener noreferrer"
aria-label="Projeyi canlı aç"
className="text-[var(--sky-600)] transition-colors hover:text-[var(--navy)]"
>
<ExternalLink className="size-4" />
</a>
) : (
<ArrowUpRight className="size-5 text-[var(--muted)] transition-colors group-hover:text-[var(--sky-600)]" />
)}
</div>
<p className="mt-2 text-sm leading-relaxed text-[var(--muted)] line-clamp-3">
{p.description}
</p>
{p.technologies && p.technologies.length > 0 && (
<div className="mt-4 flex flex-wrap gap-1.5">
{p.technologies.map((t) => (
<span
key={t}
className="rounded-md bg-[var(--navy-50)] px-2 py-0.5 text-xs font-medium text-[var(--navy-700)]"
>
{t}
</span>
))}
</div>
)}
{p.category && (
<span className="absolute left-4 top-4 rounded-full bg-white/95 px-3 py-1 text-xs font-medium text-[var(--navy)] shadow-sm">
{p.category}
</span>
)}
</div>
</Link>
<div className="p-6">
<div className="flex items-start justify-between gap-3">
<Link href={`/projeler/${p.slug}`} className="block">
<h3 className="text-lg font-semibold text-[var(--navy)] transition group-hover:text-[var(--sky-600)]">
{p.title}
</h3>
</Link>
{p.live_url ? (
<a
href={p.live_url}
target="_blank"
rel="noopener noreferrer"
aria-label="Projeyi canlı aç"
className="text-[var(--sky-600)] hover:text-[var(--navy)]"
>
<ExternalLink className="size-4" />
</a>
) : (
<ArrowUpRight className="size-5 text-[var(--muted)] transition group-hover:text-[var(--sky-600)]" />
)}
</div>
<p className="mt-2 text-sm leading-relaxed text-[var(--muted)] line-clamp-3">
{p.description}
</p>
{p.technologies && p.technologies.length > 0 && (
<div className="mt-4 flex flex-wrap gap-1.5">
{p.technologies.map((t) => (
<span
key={t}
className="rounded-md bg-[var(--navy-50)] px-2 py-0.5 text-xs text-[var(--navy-700)]"
>
{t}
</span>
))}
</div>
)}
</div>
</article>
))}
</article>
);
})}
</div>
);
}