diff --git a/app/actions.ts b/app/actions.ts new file mode 100644 index 0000000..59cafc9 --- /dev/null +++ b/app/actions.ts @@ -0,0 +1,55 @@ +"use server"; + +import { ID } from "node-appwrite"; +import { serverTablesDB, DATABASE_ID, TABLES } from "@/lib/appwrite-server"; + +export type ContactFormState = { + ok: boolean; + message: string; + errors?: Record; +}; + +const initial: ContactFormState = { ok: false, message: "" }; + +export async function submitContact( + _prev: ContactFormState = initial, + formData: FormData, +): Promise { + const name = String(formData.get("name") ?? "").trim(); + const email = String(formData.get("email") ?? "").trim(); + const phone = String(formData.get("phone") ?? "").trim(); + const subject = String(formData.get("subject") ?? "").trim(); + const message = String(formData.get("message") ?? "").trim(); + + const errors: Record = {}; + if (!name) errors.name = "Ad zorunlu"; + if (!email) errors.email = "E-posta zorunlu"; + else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) + errors.email = "Geçerli bir e-posta girin"; + if (!message || message.length < 10) + errors.message = "Mesaj en az 10 karakter olmalı"; + + if (Object.keys(errors).length > 0) { + return { ok: false, message: "Lütfen form alanlarını kontrol edin", errors }; + } + + try { + await serverTablesDB.createRow({ + databaseId: DATABASE_ID, + tableId: TABLES.contactMessages, + rowId: ID.unique(), + data: { + name, + email, + phone: phone || null, + subject: subject || null, + message, + status: "new", + }, + }); + return { ok: true, message: "Mesajınız iletildi. En kısa sürede dönüş yapacağız." }; + } catch (err) { + const detail = err instanceof Error ? err.message : "Bilinmeyen hata"; + return { ok: false, message: `Kayıt başarısız: ${detail}` }; + } +} diff --git a/app/globals.css b/app/globals.css index a2dc41e..a2ec23d 100644 --- a/app/globals.css +++ b/app/globals.css @@ -2,25 +2,57 @@ :root { --background: #ffffff; - --foreground: #171717; + --foreground: #0a0f1c; + --navy: #0f2c5c; + --navy-700: #15407f; + --navy-50: #eef3fb; + --sky: #4da3c7; + --sky-600: #2f87ad; + --sky-50: #ecf6fb; + --muted: #5b6577; + --border: #e5e9f0; } @theme inline { --color-background: var(--background); --color-foreground: var(--foreground); + --color-navy: var(--navy); + --color-navy-700: var(--navy-700); + --color-navy-50: var(--navy-50); + --color-sky-brand: var(--sky); + --color-sky-brand-600: var(--sky-600); + --color-sky-brand-50: var(--sky-50); + --color-muted-foreground: var(--muted); + --color-border-soft: var(--border); --font-sans: var(--font-geist-sans); --font-mono: var(--font-geist-mono); } -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } -} - body { background: var(--background); color: var(--foreground); - font-family: Arial, Helvetica, sans-serif; + font-family: var(--font-sans), Arial, Helvetica, sans-serif; + -webkit-font-smoothing: antialiased; +} + +.hero-grid { + background-image: + radial-gradient(circle at 1px 1px, rgba(15, 44, 92, 0.08) 1px, transparent 0); + background-size: 24px 24px; +} + +.gradient-text { + background: linear-gradient(90deg, var(--navy) 0%, var(--sky) 100%); + -webkit-background-clip: text; + background-clip: text; + color: transparent; +} + +@keyframes float-slow { + 0%, 100% { transform: translateY(0); } + 50% { transform: translateY(-12px); } +} + +.animate-float { + animation: float-slow 6s ease-in-out infinite; } diff --git a/app/hakkimizda/page.tsx b/app/hakkimizda/page.tsx new file mode 100644 index 0000000..f9e6cd0 --- /dev/null +++ b/app/hakkimizda/page.tsx @@ -0,0 +1,92 @@ +import type { Metadata } from "next"; +import Image from "next/image"; +import { SectionTitle } from "@/components/section-title"; +import { CheckCircle2 } from "lucide-react"; + +export const metadata: Metadata = { + title: "Hakkımızda", + description: + "Kovak Yazılım, Kocaeli merkezli bir teknoloji ajansıdır. Web, mobil ve CRM çözümleri üretir.", +}; + +const values = [ + { + title: "Uçtan uca üretim", + description: + "Fikir aşamasından lansmana, lansman sonrası bakıma kadar tek bir ekip.", + }, + { + title: "Ölçülebilir sonuç", + description: + "Her projeyi performans, dönüşüm ve kullanıcı deneyimi metrikleriyle değerlendiriyoruz.", + }, + { + title: "Şeffaf süreç", + description: + "Her sprint demo ile başlar, her engel açıkça konuşulur. Sürprize yer yok.", + }, + { + title: "Uzun vadeli ortaklık", + description: + "Proje biter, iş büyür. Bakım ve geliştirme süreçlerinde yanınızdayız.", + }, +]; + +export default function AboutPage() { + return ( + <> +
+
+
+ + +
    + {values.map((v) => ( +
  • + +
    +

    {v.title}

    +

    {v.description}

    +
    +
  • + ))} +
+
+ +
+
+
+ Kovak Yazılım +
+
+
+
+ +
+
+ {[ + { value: "50+", label: "Tamamlanan proje" }, + { value: "30+", label: "Mutlu müşteri" }, + { value: "10+", label: "Yıllık deneyim" }, + ].map((s) => ( +
+

{s.value}

+

{s.label}

+
+ ))} +
+
+ + ); +} diff --git a/app/hizmetler/page.tsx b/app/hizmetler/page.tsx new file mode 100644 index 0000000..9feb324 --- /dev/null +++ b/app/hizmetler/page.tsx @@ -0,0 +1,27 @@ +import type { Metadata } from "next"; +import { SectionTitle } from "@/components/section-title"; +import { ServicesGrid } from "@/components/services-grid"; +import { listServices } from "@/lib/data"; + +export const metadata: Metadata = { + title: "Hizmetler", + description: + "Web tasarım, e-ticaret, mobil uygulama, yazılım geliştirme, CRM ve dijital pazarlama hizmetleri.", +}; + +export default async function ServicesPage() { + const services = await listServices(); + + return ( +
+ +
+ +
+
+ ); +} diff --git a/app/iletisim/page.tsx b/app/iletisim/page.tsx new file mode 100644 index 0000000..6119286 --- /dev/null +++ b/app/iletisim/page.tsx @@ -0,0 +1,96 @@ +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 { siteConfig } from "@/lib/site-config"; + +export const metadata: Metadata = { + title: "İletişim", + description: + "Projeniz hakkında konuşmak için bize ulaşın. İzmit Sanayi Sitesi, Kocaeli.", +}; + +export default function ContactPage() { + return ( +
+ + +
+
+ +
+ +
+ } + title="Adres" + content={siteConfig.contact.address} + /> + } + title="Telefon" + content={ + + {siteConfig.contact.phone} + + } + /> + } + title="E-posta" + content={ + + {siteConfig.contact.email} + + } + /> + } + title="Çalışma Saatleri" + content={ + <> + Hafta içi 09:00 — 18:00 +
+ Cumartesi 10:00 — 14:00 + + } + /> +
+
+
+ ); +} + +function InfoCard({ + icon, + title, + content, +}: { + icon: React.ReactNode; + title: string; + content: React.ReactNode; +}) { + return ( +
+
+ {icon} +
+
+

+ {title} +

+
{content}
+
+
+ ); +} diff --git a/app/layout.tsx b/app/layout.tsx index 976eb90..8247449 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,6 +1,9 @@ import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; +import { Header } from "@/components/header"; +import { Footer } from "@/components/footer"; +import { siteConfig } from "@/lib/site-config"; const geistSans = Geist({ variable: "--font-geist-sans", @@ -13,21 +16,34 @@ const geistMono = Geist_Mono({ }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: { + default: `${siteConfig.name} — Yazılım, Web ve CRM Çözümleri`, + template: `%s | ${siteConfig.name}`, + }, + description: siteConfig.tagline, + metadataBase: new URL(siteConfig.url), + openGraph: { + title: siteConfig.name, + description: siteConfig.tagline, + locale: "tr_TR", + type: "website", + }, + icons: { icon: "/logo.png" }, }; export default function RootLayout({ children, -}: Readonly<{ - children: React.ReactNode; -}>) { +}: Readonly<{ children: React.ReactNode }>) { return ( - {children} + +
+
{children}
+