feat: hizmet ve proje detay sayfaları + galeri sistemi

Yeni Appwrite kolonları:
- services: content (markdown), features[], faq[] (JSON-encoded), hero_image
- projects: gallery[], content (markdown), client_name, industry, duration, service_slug

Public sayfalar:
- /hizmetler/[slug]: hero + features checklist + markdown content + FAQ accordion
  + ilgili projeler (service_slug eşleşmesi)
- /projeler/[slug]: hero + meta tablosu (müşteri/sektör/süre/yıl) + kapak görseli
  + markdown vaka çalışması + lightbox galeri + diğer projeler

Yeni componentler:
- components/gallery.tsx: lightbox galeri (keyboard nav, prev/next, ESC kapat)
- components/faq-list.tsx: accordion FAQ (tek seferde tek açık)

Admin formları:
- Hizmet formu: hero_image, content (markdown), features (virgülle), FAQ
  (her blok '---' ile ayrılır, ilk satır soru, kalanı cevap)
- Proje formu: gallery (her satıra bir URL), content (markdown), client_name,
  industry, duration, service_slug (dropdown — hizmetlerden seçim)

Linkler:
- ServicesGrid kartları → /hizmetler/[slug]
- ProjectsGrid kartları → /projeler/[slug] (live_url butonu ayrı, target=_blank)

29 route üretiliyor.
This commit is contained in:
Ege Can Komur
2026-05-20 02:46:11 +03:00
parent edd0af76dc
commit c0da5ae8d3
13 changed files with 792 additions and 47 deletions
+11 -4
View File
@@ -1,3 +1,5 @@
import Link from "next/link";
import { ArrowUpRight } from "lucide-react";
import { Icon } from "@/components/icon";
import { siteConfig } from "@/lib/site-config";
import type { ServiceRow } from "@/lib/types";
@@ -18,24 +20,29 @@ export function ServicesGrid({ services }: { services: ServiceRow[] }) {
return (
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
{items.map((s) => (
<article
<Link
key={s.slug}
href={`/hizmetler/${s.slug}`}
id={s.slug}
className="group relative overflow-hidden rounded-2xl border border-[var(--border)] bg-white p-6 transition hover:border-[var(--sky)]/40 hover:shadow-lg hover:shadow-[var(--sky)]/10"
>
<div className="absolute -right-12 -top-12 size-32 rounded-full bg-[var(--sky-50)] opacity-0 transition group-hover:opacity-100" aria-hidden />
<div
className="absolute -right-12 -top-12 size-32 rounded-full bg-[var(--sky-50)] opacity-0 transition group-hover:opacity-100"
aria-hidden
/>
<ArrowUpRight className="absolute right-5 top-5 size-4 text-[var(--muted)] transition group-hover:text-[var(--sky-600)]" />
<div className="relative">
<div className="flex size-12 items-center justify-center rounded-xl bg-[var(--navy-50)] text-[var(--navy)]">
<Icon name={s.icon} className="size-6" />
</div>
<h3 className="mt-5 text-lg font-semibold text-[var(--navy)]">
<h3 className="mt-5 text-lg font-semibold text-[var(--navy)] transition group-hover:text-[var(--sky-600)]">
{s.title}
</h3>
<p className="mt-2 text-sm leading-relaxed text-[var(--muted)]">
{s.description}
</p>
</div>
</article>
</Link>
))}
</div>
);