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:
@@ -0,0 +1,188 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { ArrowRight, MessageCircle, Phone, Tag } from "lucide-react";
|
||||
import {
|
||||
getSiteSettings,
|
||||
listPublishedPosts,
|
||||
listServices,
|
||||
} from "@/lib/data";
|
||||
import { siteConfig } from "@/lib/site-config";
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
* Hangi yazıyı/sayfayı görüntülüyoruz — listede gizlemek için.
|
||||
*/
|
||||
currentSlug?: string;
|
||||
}
|
||||
|
||||
export async function ContentSidebar({ currentSlug }: Props) {
|
||||
const [settings, services, posts] = await Promise.all([
|
||||
getSiteSettings(),
|
||||
listServices(),
|
||||
listPublishedPosts({ limit: 5 }),
|
||||
]);
|
||||
|
||||
const phoneRaw = settings?.contact_phone_raw ?? siteConfig.contact.phoneRaw;
|
||||
const phone = settings?.contact_phone ?? siteConfig.contact.phone;
|
||||
const waCleaned = phoneRaw.replace(/[^\d]/g, "");
|
||||
const waMessage = settings?.whatsapp_message ?? "";
|
||||
const waHref = `https://wa.me/${waCleaned}${
|
||||
waMessage ? `?text=${encodeURIComponent(waMessage)}` : ""
|
||||
}`;
|
||||
|
||||
const otherPosts = posts.filter((p) => p.slug !== currentSlug).slice(0, 4);
|
||||
|
||||
// Etiket sayımı (tüm yazılardan toplu)
|
||||
const tagCount = new Map<string, number>();
|
||||
posts.forEach((p) =>
|
||||
(p.tags ?? []).forEach((t) =>
|
||||
tagCount.set(t, (tagCount.get(t) ?? 0) + 1),
|
||||
),
|
||||
);
|
||||
const topTags = Array.from(tagCount.entries())
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.slice(0, 10);
|
||||
|
||||
return (
|
||||
<aside className="space-y-6 lg:sticky lg:top-24 lg:self-start">
|
||||
{/* CTA card */}
|
||||
<div className="overflow-hidden rounded-2xl border border-[var(--border)] bg-gradient-to-br from-[var(--navy)] to-[var(--sky-600)] p-6 text-white">
|
||||
<h3 className="text-base font-bold">Projeniz mi var?</h3>
|
||||
<p className="mt-2 text-sm text-white/80">
|
||||
Ücretsiz keşif görüşmesi için bizi arayın veya WhatsApp'tan yazın.
|
||||
</p>
|
||||
<div className="mt-4 space-y-2">
|
||||
<a
|
||||
href={`tel:${phoneRaw}`}
|
||||
className="flex items-center justify-center gap-2 rounded-xl bg-white px-4 py-2.5 text-sm font-semibold text-[var(--navy)] transition hover:bg-blue-50"
|
||||
>
|
||||
<Phone className="size-3.5" />
|
||||
{phone}
|
||||
</a>
|
||||
<a
|
||||
href={waHref}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center justify-center gap-2 rounded-xl bg-[#25d366] px-4 py-2.5 text-sm font-semibold text-white transition hover:bg-[#1ebe5d]"
|
||||
>
|
||||
<MessageCircle className="size-3.5" />
|
||||
WhatsApp'tan yaz
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Diğer yazılar */}
|
||||
{otherPosts.length > 0 && (
|
||||
<div className="rounded-2xl border border-[var(--border)] bg-white p-5">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-sm font-bold uppercase tracking-wider text-[var(--navy)]">
|
||||
Son Yazılar
|
||||
</h3>
|
||||
<Link
|
||||
href="/blog"
|
||||
className="text-xs text-[var(--sky-600)] hover:text-[var(--navy)]"
|
||||
>
|
||||
Tümü →
|
||||
</Link>
|
||||
</div>
|
||||
<ul className="mt-4 space-y-3">
|
||||
{otherPosts.map((p) => (
|
||||
<li key={p.$id}>
|
||||
<Link
|
||||
href={`/blog/${p.slug}`}
|
||||
className="group flex gap-3"
|
||||
>
|
||||
<div className="relative size-16 shrink-0 overflow-hidden rounded-lg bg-[var(--navy-50)]">
|
||||
{p.cover_image ? (
|
||||
<Image
|
||||
src={p.cover_image}
|
||||
alt={p.title}
|
||||
fill
|
||||
sizes="64px"
|
||||
className="object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="flex h-full items-center justify-center text-lg font-bold text-[var(--navy)]/30">
|
||||
{p.title.charAt(0)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="line-clamp-2 text-sm font-medium leading-snug text-[var(--navy)] transition-colors group-hover:text-[var(--sky-600)]">
|
||||
{p.title}
|
||||
</p>
|
||||
{p.published_at && (
|
||||
<p className="mt-1 text-[11px] text-[var(--muted)]">
|
||||
{new Date(p.published_at).toLocaleDateString("tr-TR")}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Etiketler */}
|
||||
{topTags.length > 0 && (
|
||||
<div className="rounded-2xl border border-[var(--border)] bg-white p-5">
|
||||
<h3 className="flex items-center gap-1.5 text-sm font-bold uppercase tracking-wider text-[var(--navy)]">
|
||||
<Tag className="size-3.5" />
|
||||
Etiketler
|
||||
</h3>
|
||||
<div className="mt-3 flex flex-wrap gap-1.5">
|
||||
{topTags.map(([tag]) => (
|
||||
<span
|
||||
key={tag}
|
||||
className="rounded-md bg-[var(--navy-50)] px-2.5 py-1 text-xs font-medium text-[var(--navy-700)] hover:bg-[var(--sky-50)]"
|
||||
>
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Hizmetler */}
|
||||
{services.length > 0 && (
|
||||
<div className="rounded-2xl border border-[var(--border)] bg-white p-5">
|
||||
<h3 className="text-sm font-bold uppercase tracking-wider text-[var(--navy)]">
|
||||
Hizmetlerimiz
|
||||
</h3>
|
||||
<ul className="mt-3 space-y-1.5">
|
||||
{services.slice(0, 6).map((s) => (
|
||||
<li key={s.slug}>
|
||||
<Link
|
||||
href={`/hizmetler/${s.slug}`}
|
||||
className="flex items-center justify-between rounded-lg px-2 py-1.5 text-sm text-[var(--foreground)] transition hover:bg-[var(--navy-50)] hover:text-[var(--navy)]"
|
||||
>
|
||||
<span>{s.title}</span>
|
||||
<ArrowRight className="size-3 text-[var(--muted)]" />
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Site analizi lead magnet */}
|
||||
<div className="rounded-2xl border border-[var(--sky)]/30 bg-[var(--sky-50)]/50 p-5">
|
||||
<h3 className="text-sm font-bold text-[var(--navy)]">
|
||||
Ücretsiz Site Analizi
|
||||
</h3>
|
||||
<p className="mt-2 text-xs leading-relaxed text-[var(--muted)]">
|
||||
Sitenizin SEO, hız ve dönüşüm performansını ücretsiz değerlendirelim.
|
||||
24 saat içinde rapor e-postanızda.
|
||||
</p>
|
||||
<Link
|
||||
href="/site-analizi"
|
||||
className="mt-3 inline-flex items-center gap-1 text-xs font-semibold text-[var(--sky-600)] hover:text-[var(--navy)]"
|
||||
>
|
||||
Hemen başla
|
||||
<ArrowRight className="size-3" />
|
||||
</Link>
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user