fix: blog empty state + proje detay yarı boş meta tablosu
Claude vision ile localhost'ta yapılan tarama sonrası 2 sorun:
1) Blog sayfası — henüz yazı yoksa empty state küçük bir kart olup
altında ~1000px beyaz alan kalıyordu, footer çok aşağıdaydı.
Çözüm: Empty state için zengin bir layout:
- Gradient hero ('Blog yazılarımızı hazırlıyoruz' + 3 CTA:
keşif görüşmesi / WhatsApp / Telefon)
- 'Bu arada hizmetlerimize göz atın' başlıkla 6 hizmet grid
- 'Site analiz raporu' lead magnet kartı
Yazı geldiğinde otomatik normal grid'e döner.
2) Proje detay sayfası — sağ üstte 2 sütunlu meta card sadece
'Yıl: 2025' gösteriyordu (client_name/industry/duration boş),
yarı boş görünüyor + sağ tarafta büyük boşluk.
Çözüm:
- meta.length >= 2 → eski 2x2 grid card
- meta.length === 1 → inline pill strip altta
- meta yok → grid tek sütuna döner (lg:grid-cols-[1.4fr_1fr]
conditional)
Claude vision ile 10 sayfa screenshot alındı (/tmp/kovak-screenshots).
Diğer sayfalar (anasayfa, hizmet detay, sektör, iletişim, vs)
tasarım açısından temiz görünüyor.
This commit is contained in:
+161
-13
@@ -1,21 +1,49 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import type { Metadata } from "next";
|
||||
import { ArrowRight, Calendar } from "lucide-react";
|
||||
import {
|
||||
ArrowRight,
|
||||
Calendar,
|
||||
Sparkles,
|
||||
MessageCircle,
|
||||
Phone,
|
||||
FileText,
|
||||
} from "lucide-react";
|
||||
import { SectionTitle } from "@/components/section-title";
|
||||
import { listPublishedPosts } from "@/lib/data";
|
||||
import { Icon } from "@/components/icon";
|
||||
import {
|
||||
getSiteSettings,
|
||||
listPublishedPosts,
|
||||
listServices,
|
||||
} from "@/lib/data";
|
||||
import { buildMetadata } from "@/lib/seo";
|
||||
import { siteConfig } from "@/lib/site-config";
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
return buildMetadata("/blog", {
|
||||
title: "Blog",
|
||||
description: "Yazılım, web tasarım, SEO ve dijital pazarlama üzerine yazılar.",
|
||||
description:
|
||||
"Yazılım, web tasarım, SEO ve dijital pazarlama üzerine yazılar.",
|
||||
});
|
||||
}
|
||||
|
||||
export default async function BlogIndex() {
|
||||
const posts = await listPublishedPosts();
|
||||
const [posts, services, settings] = await Promise.all([
|
||||
listPublishedPosts(),
|
||||
listServices(),
|
||||
getSiteSettings(),
|
||||
]);
|
||||
|
||||
const phoneRaw = settings?.contact_phone_raw ?? siteConfig.contact.phoneRaw;
|
||||
const phone = settings?.contact_phone ?? siteConfig.contact.phone;
|
||||
const wa = phoneRaw.replace(/[^\d]/g, "");
|
||||
const waMessage = settings?.whatsapp_message ?? "";
|
||||
const waHref = `https://wa.me/${wa}${
|
||||
waMessage ? `?text=${encodeURIComponent(waMessage)}` : ""
|
||||
}`;
|
||||
|
||||
// Empty state — site daha yeni, içerik yok
|
||||
if (posts.length === 0) {
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl px-6 py-20">
|
||||
<SectionTitle
|
||||
@@ -24,15 +52,137 @@ export default async function BlogIndex() {
|
||||
description="Sektörden notlar, vaka çalışmaları ve teknik rehberler."
|
||||
/>
|
||||
|
||||
<div className="mt-14">
|
||||
{posts.length === 0 ? (
|
||||
<div className="rounded-2xl border border-dashed border-[var(--border)] bg-[var(--navy-50)]/40 p-12 text-center">
|
||||
<p className="text-sm text-[var(--muted)]">
|
||||
Henüz yayınlanmış yazı yok.
|
||||
{/* Coming soon hero */}
|
||||
<div className="relative mt-14 overflow-hidden rounded-3xl bg-gradient-to-br from-[var(--navy)] via-[var(--sky-600)] to-[var(--sky)] p-12 text-center text-white shadow-xl shadow-[var(--navy)]/15">
|
||||
<div
|
||||
className="absolute inset-0 opacity-10"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"radial-gradient(circle at 1px 1px, white 1px, transparent 0)",
|
||||
backgroundSize: "24px 24px",
|
||||
}}
|
||||
aria-hidden
|
||||
/>
|
||||
<div className="relative">
|
||||
<span className="inline-flex items-center gap-2 rounded-full border border-white/30 bg-white/10 px-4 py-1.5 text-xs font-medium backdrop-blur">
|
||||
<Sparkles className="size-3.5" />
|
||||
Yakında
|
||||
</span>
|
||||
<h2 className="mt-5 text-3xl font-bold sm:text-4xl">
|
||||
Blog yazılarımızı hazırlıyoruz
|
||||
</h2>
|
||||
<p className="mx-auto mt-4 max-w-xl text-base text-white/80">
|
||||
Sektörden vaka çalışmaları, teknik rehberler ve sahada öğrendiklerimizi
|
||||
kısa sürede burada paylaşmaya başlayacağız.
|
||||
</p>
|
||||
|
||||
<div className="mt-8 flex flex-wrap items-center justify-center gap-3">
|
||||
<Link
|
||||
href="/iletisim"
|
||||
className="inline-flex items-center gap-2 rounded-xl bg-white px-5 py-3 text-sm font-semibold text-[var(--navy)] transition hover:-translate-y-0.5 hover:bg-blue-50"
|
||||
>
|
||||
Ücretsiz keşif görüşmesi
|
||||
<ArrowRight className="size-4" />
|
||||
</Link>
|
||||
<a
|
||||
href={waHref}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-2 rounded-xl bg-[#25d366] px-5 py-3 text-sm font-semibold text-white transition hover:-translate-y-0.5 hover:bg-[#1ebe5d]"
|
||||
>
|
||||
<MessageCircle className="size-4" />
|
||||
WhatsApp
|
||||
</a>
|
||||
<a
|
||||
href={`tel:${phoneRaw}`}
|
||||
className="inline-flex items-center gap-2 rounded-xl border border-white/30 bg-white/5 px-5 py-3 text-sm font-semibold text-white backdrop-blur transition hover:border-white/60"
|
||||
>
|
||||
<Phone className="size-4" />
|
||||
{phone}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bu arada → Hizmetler grid */}
|
||||
{services.length > 0 && (
|
||||
<section className="mt-16">
|
||||
<div className="flex items-end justify-between">
|
||||
<SectionTitle
|
||||
align="left"
|
||||
eyebrow="Bu arada"
|
||||
title="Hizmetlerimize göz atın"
|
||||
description="Blog yazılarımızı beklerken sunduğumuz çözümleri keşfedin."
|
||||
/>
|
||||
<Link
|
||||
href="/hizmetler"
|
||||
className="hidden text-sm font-medium text-[var(--sky-600)] hover:text-[var(--navy)] sm:inline-flex"
|
||||
>
|
||||
Tümünü gör →
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="mt-10 grid gap-5 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{services.slice(0, 6).map((s) => (
|
||||
<Link
|
||||
key={s.slug}
|
||||
href={`/hizmetler/${s.slug}`}
|
||||
className="group relative overflow-hidden rounded-2xl border border-[var(--border)] bg-white p-6 transition-all duration-300 hover:-translate-y-1 hover:border-[var(--sky)]/40 hover:shadow-xl hover:shadow-[var(--navy)]/10"
|
||||
>
|
||||
<div className="flex size-12 items-center justify-center rounded-xl bg-gradient-to-br from-[var(--sky)] to-purple-500 text-white shadow-lg">
|
||||
<Icon name={s.icon} className="size-5" />
|
||||
</div>
|
||||
<h3 className="mt-5 text-base font-bold text-[var(--navy)] group-hover:text-[var(--sky-600)]">
|
||||
{s.title}
|
||||
</h3>
|
||||
<p className="mt-2 text-sm leading-relaxed text-[var(--muted)] line-clamp-2">
|
||||
{s.description}
|
||||
</p>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Lead magnet CTA */}
|
||||
<section className="mt-16 rounded-2xl border border-dashed border-[var(--sky)]/40 bg-[var(--sky-50)]/40 p-8 sm:p-10">
|
||||
<div className="flex flex-col items-start gap-6 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-[var(--sky-600)]">
|
||||
<FileText className="mr-1 inline size-3.5" />
|
||||
Ücretsiz Rapor
|
||||
</p>
|
||||
<h3 className="mt-2 text-2xl font-bold text-[var(--navy)]">
|
||||
Site analiz raporunuzu alın
|
||||
</h3>
|
||||
<p className="mt-2 max-w-xl text-sm text-[var(--muted)]">
|
||||
Mevcut sitenizin SEO, hız, mobil ve dönüşüm performansını ücretsiz
|
||||
değerlendirelim. 24 saat içinde detaylı rapor e-postanızda.
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
|
||||
<Link
|
||||
href="/site-analizi"
|
||||
className="inline-flex items-center gap-2 rounded-xl bg-[var(--navy)] px-6 py-3 text-sm font-semibold text-white shadow-lg shadow-[var(--navy)]/20 transition hover:-translate-y-0.5 hover:bg-[var(--navy-700)]"
|
||||
>
|
||||
Ücretsiz raporumu istiyorum
|
||||
<ArrowRight className="size-4" />
|
||||
</Link>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Normal grid — yazı varsa
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl px-6 py-20">
|
||||
<SectionTitle
|
||||
eyebrow="Blog"
|
||||
title="Yazılım, tasarım ve büyüme üzerine"
|
||||
description="Sektörden notlar, vaka çalışmaları ve teknik rehberler."
|
||||
/>
|
||||
|
||||
<div className="mt-14 grid gap-8 md:grid-cols-2 lg:grid-cols-3">
|
||||
{posts.map((p) => (
|
||||
<article
|
||||
key={p.$id}
|
||||
@@ -77,8 +227,6 @@ export default async function BlogIndex() {
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,11 @@ export default async function ProjectDetailPage({
|
||||
<ArrowLeft className="size-3.5" /> Tüm projeler
|
||||
</Link>
|
||||
|
||||
<div className="mt-6 grid items-start gap-10 lg:grid-cols-[1.4fr_1fr]">
|
||||
<div
|
||||
className={`mt-6 grid items-start gap-10 ${
|
||||
meta.length >= 2 ? "lg:grid-cols-[1.4fr_1fr]" : ""
|
||||
}`}
|
||||
>
|
||||
<div>
|
||||
{project.category && (
|
||||
<span className="inline-flex rounded-full bg-[var(--sky-50)] px-3 py-1 text-xs font-medium text-[var(--sky-600)]">
|
||||
@@ -128,7 +132,8 @@ export default async function ProjectDetailPage({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{meta.length > 0 && (
|
||||
{/* Meta tablo sadece 2+ alan dolu ise gösterilir — yarı boş card görünmesin */}
|
||||
{meta.length >= 2 && (
|
||||
<dl className="grid grid-cols-2 gap-4 rounded-2xl border border-[var(--border)] bg-white p-6">
|
||||
{meta.map((m) => (
|
||||
<div key={m.label}>
|
||||
@@ -145,6 +150,22 @@ export default async function ProjectDetailPage({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Tek-iki meta varsa daha kompakt inline strip olarak gösterilir */}
|
||||
{meta.length > 0 && meta.length < 2 && (
|
||||
<div className="mt-6 flex flex-wrap gap-3">
|
||||
{meta.map((m) => (
|
||||
<span
|
||||
key={m.label}
|
||||
className="inline-flex items-center gap-1.5 rounded-full border border-[var(--border)] bg-white px-3 py-1.5 text-xs text-[var(--muted)]"
|
||||
>
|
||||
{m.icon}
|
||||
<span className="font-medium text-[var(--navy)]">{m.label}:</span>{" "}
|
||||
{m.value}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{project.image_url && (
|
||||
<div className="relative mt-10 aspect-video overflow-hidden rounded-2xl">
|
||||
<Image
|
||||
|
||||
Reference in New Issue
Block a user