From 1444aa3995e707c8a338161e21da1e4d4b6f4996 Mon Sep 17 00:00:00 2001 From: Ege Can Komur Date: Wed, 20 May 2026 02:56:45 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20anasayfa=20i=C3=A7eri=C4=9Fi,=20ileti?= =?UTF-8?q?=C5=9Fim=20ve=20sosyal=20medya=20y=C3=B6netilebilir?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Yeni site_settings tablosu (singleton, rowId='homepage'): - Hero: badge, title, subtitle, 2 CTA (label+href), stats (JSON array) - Section başlıkları: services/projects/testimonials eyebrow + title + description - Alt CTA: title, description, button label+href - Contact: phone (görünen + tel: ham), email, address, hafta içi/sonu saatleri - Social: linkedin/instagram/twitter/facebook URL'leri - Footer tagline Mevcut hardcoded değerler seed edildi. Admin: - /admin/site sayfası eklendi (sidebar'a 'Site Ayarları' linki) - Bölümlü tek form: Hero / Hizmetler / Projeler / Referanslar / Alt CTA / İletişim / Sosyal / Footer - Stats için 'değer | etiket' satır formatı Public bağlantılar: - Hero component artık settings prop alıyor (fallback değerlerle) - Anasayfa: tüm section başlıkları ve alt CTA settings'ten geliyor - Header: telefon settings'ten - Footer: tagline, adres, telefon, email, sosyal linkler settings'ten (sosyal link sadece dolu olanlar gösteriliyor) - Footer'da hizmetler artık /hizmetler/[slug] detay sayfalarına bağlı - İletişim sayfası: adres, telefon, email, saatler settings'ten 30 route üretiliyor. --- app/(site)/iletisim/page.tsx | 25 ++- app/(site)/page.tsx | 51 +++-- app/admin/(protected)/site/page.tsx | 308 ++++++++++++++++++++++++++++ components/admin/sidebar.tsx | 2 + components/footer.tsx | 96 +++++---- components/header.tsx | 13 +- components/hero.tsx | 77 +++++-- lib/admin-actions.ts | 79 +++++++ lib/appwrite-rest.ts | 1 + lib/data.ts | 13 ++ lib/types.ts | 47 +++++ 11 files changed, 621 insertions(+), 91 deletions(-) create mode 100644 app/admin/(protected)/site/page.tsx diff --git a/app/(site)/iletisim/page.tsx b/app/(site)/iletisim/page.tsx index bf28ac6..feb3ce5 100644 --- a/app/(site)/iletisim/page.tsx +++ b/app/(site)/iletisim/page.tsx @@ -2,6 +2,7 @@ import type { Metadata } from "next"; import { Mail, MapPin, Phone, Clock } from "lucide-react"; import { SectionTitle } from "@/components/section-title"; import { ContactForm } from "@/components/contact-form"; +import { getSiteSettings } from "@/lib/data"; import { siteConfig } from "@/lib/site-config"; import { buildMetadata } from "@/lib/seo"; @@ -13,7 +14,15 @@ export async function generateMetadata(): Promise { }); } -export default function ContactPage() { +export default async function ContactPage() { + const s = await getSiteSettings(); + const address = s?.contact_address ?? siteConfig.contact.address; + const phone = s?.contact_phone ?? siteConfig.contact.phone; + const phoneRaw = s?.contact_phone_raw ?? siteConfig.contact.phoneRaw; + const email = s?.contact_email ?? siteConfig.contact.email; + const weekday = s?.contact_hours_weekday ?? "Hafta içi 09:00 — 18:00"; + const weekend = s?.contact_hours_weekend ?? "Cumartesi 10:00 — 14:00"; + return (
} title="Adres" - content={siteConfig.contact.address} + content={address} /> } title="Telefon" content={ - {siteConfig.contact.phone} + {phone} } /> @@ -50,10 +59,10 @@ export default function ContactPage() { title="E-posta" content={ - {siteConfig.contact.email} + {email} } /> @@ -62,9 +71,9 @@ export default function ContactPage() { title="Çalışma Saatleri" content={ <> - Hafta içi 09:00 — 18:00 + {weekday}
- Cumartesi 10:00 — 14:00 + {weekend} } /> diff --git a/app/(site)/page.tsx b/app/(site)/page.tsx index b6e0ae4..36f004a 100644 --- a/app/(site)/page.tsx +++ b/app/(site)/page.tsx @@ -6,7 +6,12 @@ import { SectionTitle } from "@/components/section-title"; import { ServicesGrid } from "@/components/services-grid"; import { ProjectsGrid } from "@/components/projects-grid"; import { TestimonialsCarousel } from "@/components/testimonials"; -import { listProjects, listServices, listTestimonials } from "@/lib/data"; +import { + getSiteSettings, + listProjects, + listServices, + listTestimonials, +} from "@/lib/data"; import { buildMetadata } from "@/lib/seo"; export async function generateMetadata(): Promise { @@ -14,22 +19,26 @@ export async function generateMetadata(): Promise { } export default async function Home() { - const [services, projects, testimonials] = await Promise.all([ + const [services, projects, testimonials, settings] = await Promise.all([ listServices({ featured: true }), listProjects({ featured: true, limit: 6 }), listTestimonials({ featured: true }), + getSiteSettings(), ]); return ( <> - +
@@ -42,9 +51,12 @@ export default async function Home() {
@@ -78,17 +95,17 @@ export default async function Home() {

- Projenizi konuşalım + {settings?.cta_title ?? "Projenizi konuşalım"}

- İhtiyacınızı dinleyip size en uygun çözümü öneren bir ekip arıyorsanız, - ilk görüşme bizden. + {settings?.cta_description ?? + "İhtiyacınızı dinleyip size en uygun çözümü öneren bir ekip arıyorsanız, ilk görüşme bizden."}

- Ücretsiz keşif görüşmesi + {settings?.cta_button_label ?? "Ücretsiz keşif görüşmesi"}
diff --git a/app/admin/(protected)/site/page.tsx b/app/admin/(protected)/site/page.tsx new file mode 100644 index 0000000..b1ddc41 --- /dev/null +++ b/app/admin/(protected)/site/page.tsx @@ -0,0 +1,308 @@ +import type { Metadata } from "next"; +import { Save } from "lucide-react"; +import { + Field, + FormActions, + FormShell, + PageHeader, + PrimaryButton, + Textarea, +} from "@/components/admin/form"; +import { getSiteSettings } from "@/lib/data"; +import { saveSiteSettings } from "@/lib/admin-actions"; +import type { StatItem } from "@/lib/types"; + +export const metadata: Metadata = { title: "Site Ayarları" }; + +function statsToText(items?: string[] | null): string { + if (!items) return ""; + const parsed: StatItem[] = []; + for (const raw of items) { + try { + const obj = JSON.parse(raw) as Partial; + if (obj.value && obj.label) parsed.push({ value: obj.value, label: obj.label }); + } catch { + /* ignore */ + } + } + return parsed.map((s) => `${s.value} | ${s.label}`).join("\n"); +} + +function Section({ + title, + description, + children, +}: { + title: string; + description?: string; + children: React.ReactNode; +}) { + return ( +
+

{title}

+ {description && ( +

{description}

+ )} +
{children}
+
+ ); +} + +export default async function SiteSettingsPage() { + const s = await getSiteSettings(); + + return ( +
+ + +
+ +
+
+ + +