c0da5ae8d3
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.
50 lines
1.8 KiB
TypeScript
50 lines
1.8 KiB
TypeScript
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";
|
|
|
|
type ServiceLike = {
|
|
slug: string;
|
|
title: string;
|
|
description: string;
|
|
icon?: string | null;
|
|
};
|
|
|
|
export function ServicesGrid({ services }: { services: ServiceRow[] }) {
|
|
const items: ServiceLike[] =
|
|
services.length > 0
|
|
? services
|
|
: (siteConfig.fallbackServices as readonly ServiceLike[]).slice();
|
|
|
|
return (
|
|
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
|
|
{items.map((s) => (
|
|
<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
|
|
/>
|
|
<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)] 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>
|
|
</Link>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|