Files
ayristech_new/components/AdminClient.tsx
T

1726 lines
81 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { motion, AnimatePresence } from "framer-motion";
import { useState, useEffect } from "react";
import Link from "next/link";
import Header from "@/components/Header";
import type { Locale } from "@/i18n-config";
import { blogPosts, BlogPost } from "@/data/blog";
import { saveProject, deleteProject, saveBlogPost, deleteBlogPost, adminLogoutAction, savePartner, deletePartner } from "@/app/actions";
const expo = [0.16, 1, 0.3, 1] as [number, number, number, number];
interface ToastMsg {
text: string;
type: "success" | "info" | "alert";
}
interface ProjectData {
id?: number;
num: string;
slug: string;
title: string;
tag: string;
desc: string;
spec: string;
year: string;
client: string;
duration: string;
tech: string[];
challenge: string;
solution: string;
results: string[];
image: string;
gallery?: string[];
website?: string;
}
interface PartnerData {
id?: number;
name: string;
tag: string;
mono: string;
year: string;
desc: string;
}
export default function AdminClient({
lang,
dict,
initialProjects = [],
initialBlogPosts = [],
initialPartners = [],
}: {
lang: Locale;
dict: any;
initialProjects?: ProjectData[];
initialBlogPosts?: BlogPost[];
initialPartners?: PartnerData[];
}) {
const [activeTab, setActiveTab] = useState<"projeler" | "blog" | "partnerler" | "ayarlar">("projeler");
// Toast state
const [toast, setToast] = useState<ToastMsg | null>(null);
const showToast = (text: string, type: "success" | "info" | "alert" = "success") => {
setToast({ text, type });
};
useEffect(() => {
if (toast) {
const t = setTimeout(() => setToast(null), 3000);
return () => clearTimeout(t);
}
}, [toast]);
// Project CRUD State
const [projects, setProjects] = useState<ProjectData[]>(initialProjects);
const [searchQuery, setSearchQuery] = useState("");
const [editingProject, setEditingProject] = useState<ProjectData | null>(null);
const [isAddingNew, setIsAddingNew] = useState(false);
// Edit / New Project Form State
const [formTitle, setFormTitle] = useState("");
const [formTag, setFormTag] = useState("");
const [formDesc, setFormDesc] = useState("");
const [formSpec, setFormSpec] = useState("");
const [formYear, setFormYear] = useState("");
const [formClient, setFormClient] = useState("");
const [formDuration, setFormDuration] = useState("");
const [formTechString, setFormTechString] = useState("");
const [formChallenge, setFormChallenge] = useState("");
const [formSolution, setFormSolution] = useState("");
const [formResults, setFormResults] = useState<string[]>([]);
const [newResultItem, setNewResultItem] = useState("");
const [formImage, setFormImage] = useState("");
const [formGallery, setFormGallery] = useState<string[]>([]);
const [newGalleryItem, setNewGalleryItem] = useState("");
const [formWebsite, setFormWebsite] = useState("");
const [uploadingImage, setUploadingImage] = useState(false);
const [uploadingGallery, setUploadingGallery] = useState(false);
const handleFileUpload = async (file: File) => {
const fd = new FormData();
fd.append('file', file);
const res = await fetch('/api/upload', { method: 'POST', body: fd });
const data = await res.json();
if (!res.ok) throw new Error(data.error || 'Yükleme başarısız');
return data.url;
};
// Blog CRUD State
const [posts, setPosts] = useState<BlogPost[]>(initialBlogPosts);
const [blogSearchQuery, setBlogSearchQuery] = useState("");
const [editingPost, setEditingPost] = useState<BlogPost | null>(null);
const [isAddingNewPost, setIsAddingNewPost] = useState(false);
// Partner CRUD State
const [partners, setPartners] = useState<PartnerData[]>(initialPartners);
const [partnerSearchQuery, setPartnerSearchQuery] = useState("");
const [editingPartner, setEditingPartner] = useState<PartnerData | null>(null);
const [isAddingNewPartner, setIsAddingNewPartner] = useState(false);
// Edit / New Partner Form State
const [formPartnerName, setFormPartnerName] = useState("");
const [formPartnerTag, setFormPartnerTag] = useState("");
const [formPartnerMono, setFormPartnerMono] = useState("");
const [formPartnerYear, setFormPartnerYear] = useState("");
const [formPartnerDesc, setFormPartnerDesc] = useState("");
// Blog Modal Form Sub-tabs ("genel" | "tr" | "en")
const [blogFormSubTab, setBlogFormSubTab] = useState<"genel" | "tr" | "en">("genel");
const [formBlogSlug, setFormBlogSlug] = useState("");
const [formBlogDate, setFormBlogDate] = useState("");
const [formBlogAuthor, setFormBlogAuthor] = useState("");
const [formBlogAuthorRole, setFormBlogAuthorRole] = useState("");
const [formBlogImage, setFormBlogImage] = useState("");
const [formBlogTrTitle, setFormBlogTrTitle] = useState("");
const [formBlogTrExcerpt, setFormBlogTrExcerpt] = useState("");
const [formBlogTrReadingTime, setFormBlogTrReadingTime] = useState("");
const [formBlogTrCategory, setFormBlogTrCategory] = useState("");
const [formBlogTrTags, setFormBlogTrTags] = useState("");
const [formBlogTrContent, setFormBlogTrContent] = useState("");
const [formBlogEnTitle, setFormBlogEnTitle] = useState("");
const [formBlogEnExcerpt, setFormBlogEnExcerpt] = useState("");
const [formBlogEnReadingTime, setFormBlogEnReadingTime] = useState("");
const [formBlogEnCategory, setFormBlogEnCategory] = useState("");
const [formBlogEnTags, setFormBlogEnTags] = useState("");
const [formBlogEnContent, setFormBlogEnContent] = useState("");
// Site Settings Form State
const [brandName, setBrandName] = useState(dict.nav.brandName || "Ayris");
const [brandSub, setBrandSub] = useState(dict.nav.brandSub || "Tech");
const [heroBadge, setHeroBadge] = useState(dict.hero.badge || "Ayris Tech — Mühendislik Zirvesi");
const [heroTitle1, setHeroTitle1] = useState(dict.hero.titleLine1 || "Geleceği");
const [heroTitle2, setHeroTitle2] = useState(dict.hero.titleLine2 || "İnşa Ediyoruz");
const [heroDesc, setHeroDesc] = useState(dict.hero.desc || "");
const [telemetryEmail, setTelemetryEmail] = useState("info@ayristech.com");
const [telemetryHub, setTelemetryHub] = useState(dict.contact.infoBaseText || "İstanbul, Türkiye");
// Open modal for project editing
const handleStartEdit = (p: ProjectData) => {
setEditingProject(p);
setIsAddingNew(false);
setFormTitle(p.title);
setFormTag(p.tag);
setFormDesc(p.desc);
setFormSpec(p.spec);
setFormYear(p.year);
setFormClient(p.client);
setFormDuration(p.duration);
setFormTechString(p.tech.join(", "));
setFormChallenge(p.challenge);
setFormSolution(p.solution);
setFormResults([...p.results]);
setNewResultItem("");
setFormImage(p.image || "");
setFormGallery(p.gallery ? [...p.gallery] : []);
setNewGalleryItem("");
setFormWebsite(p.website || "");
};
// Open modal for project adding
const handleStartAdd = () => {
setEditingProject(null);
setIsAddingNew(true);
setFormTitle("");
setFormTag("");
setFormDesc("");
setFormSpec("");
setFormYear("2026");
setFormClient("");
setFormDuration("");
setFormTechString("");
setFormChallenge("");
setFormSolution("");
setFormResults([]);
setNewResultItem("");
setFormImage("");
setFormGallery([]);
setNewGalleryItem("");
setFormWebsite("");
};
// Save project
const handleSaveProject = async (e: React.FormEvent) => {
e.preventDefault();
if (!formTitle.trim()) {
showToast("Proje başlığı boş bırakılamaz!", "alert");
return;
}
const techArray = formTechString.split(",").map(t => t.trim()).filter(Boolean);
const slugValue = formTitle.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
const nextNum = isAddingNew
? (projects.length > 0
? String(Math.max(...projects.map(p => parseInt(p.num, 10))) + 1).padStart(2, '0')
: "01")
: editingProject!.num;
const projectDataToSave = {
id: editingProject?.id,
num: nextNum,
slug: slugValue,
title: formTitle,
tag: formTag || "Web · Yapay Zekâ",
desc: formDesc,
spec: formSpec,
year: formYear,
client: formClient,
duration: formDuration,
tech: techArray,
challenge: formChallenge,
solution: formSolution,
results: formResults.length > 0 ? formResults : ["Proje başarıyla tamamlandı"],
image: formImage,
gallery: formGallery,
website: formWebsite,
};
const res = await saveProject(projectDataToSave);
if (res.success && res.project) {
if (isAddingNew) {
setProjects([...projects, { ...projectDataToSave, id: res.project.id }]);
showToast(`[ YENİ PROJE YARATILDI // ${formTitle.toUpperCase()} ]`, "success");
setIsAddingNew(false);
} else {
const updatedList = projects.map(p => {
if (p.id === editingProject?.id) {
return {
...p,
...projectDataToSave,
};
}
return p;
});
setProjects(updatedList);
showToast(`[ PROJE BAŞARIYLA DÜZENLENDİ // ${formTitle.toUpperCase()} ]`, "success");
setEditingProject(null);
}
} else {
showToast(`Hata: ${res.error}`, "alert");
}
};
// Delete project
const handleDeleteProject = async (id: number, title: string) => {
if (confirm(`"${title}" projesini silmek istediğinize emin misiniz?`)) {
const res = await deleteProject(id);
if (res.success) {
setProjects(projects.filter(p => p.id !== id));
showToast(`[ PROJE SİLİNDİ // ${title.toUpperCase()} ]`, "alert");
} else {
showToast(`Hata: ${res.error}`, "alert");
}
}
};
// Add list result item
const handleAddResultItem = () => {
if (newResultItem.trim()) {
setFormResults([...formResults, newResultItem.trim()]);
setNewResultItem("");
}
};
// Remove list result item
const handleRemoveResultItem = (idx: number) => {
setFormResults(formResults.filter((_, i) => i !== idx));
};
// Add gallery item
const handleAddGalleryItem = () => {
if (newGalleryItem.trim()) {
setFormGallery([...formGallery, newGalleryItem.trim()]);
setNewGalleryItem("");
}
};
// Remove gallery item
const handleRemoveGalleryItem = (idx: number) => {
setFormGallery(formGallery.filter((_, i) => i !== idx));
};
// ── BLOG HANDLERS ──
// Open modal for blog editing
const handleStartEditPost = (post: BlogPost) => {
setEditingPost(post);
setIsAddingNewPost(false);
setBlogFormSubTab("genel");
setFormBlogSlug(post.slug);
setFormBlogDate(post.date);
setFormBlogAuthor(post.author);
setFormBlogAuthorRole(post.authorRole);
setFormBlogImage(post.image);
setFormBlogTrTitle(post.tr.title);
setFormBlogTrExcerpt(post.tr.excerpt);
setFormBlogTrReadingTime(post.tr.readingTime);
setFormBlogTrCategory(post.tr.category);
setFormBlogTrTags(post.tr.tags.join(", "));
setFormBlogTrContent(post.tr.content);
setFormBlogEnTitle(post.en.title);
setFormBlogEnExcerpt(post.en.excerpt);
setFormBlogEnReadingTime(post.en.readingTime);
setFormBlogEnCategory(post.en.category);
setFormBlogEnTags(post.en.tags.join(", "));
setFormBlogEnContent(post.en.content);
};
// Open modal for blog adding
const handleStartAddPost = () => {
setEditingPost(null);
setIsAddingNewPost(true);
setBlogFormSubTab("genel");
setFormBlogSlug("");
setFormBlogDate(new Date().toISOString().split('T')[0]);
setFormBlogAuthor("Mustafa Yıldız");
setFormBlogAuthorRole("Founder & Architect");
setFormBlogImage("");
setFormBlogTrTitle("");
setFormBlogTrExcerpt("");
setFormBlogTrReadingTime("5 dk okuma");
setFormBlogTrCategory("Teknoloji");
setFormBlogTrTags("AI, Web");
setFormBlogTrContent("");
setFormBlogEnTitle("");
setFormBlogEnExcerpt("");
setFormBlogEnReadingTime("5 min read");
setFormBlogEnCategory("Technology");
setFormBlogEnTags("AI, Web");
setFormBlogEnContent("");
};
// Save Blog Post
const handleSavePost = async (e: React.FormEvent) => {
e.preventDefault();
if (!formBlogTrTitle.trim()) {
showToast("Türkçe blog başlığı zorunludur!", "alert");
return;
}
const calculatedSlug = formBlogSlug.trim() ||
formBlogTrTitle.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
const blogPostDataToSave = {
id: editingPost?.id,
slug: calculatedSlug,
date: formBlogDate || new Date().toISOString().split('T')[0],
author: formBlogAuthor || "Ayris Council",
authorRole: formBlogAuthorRole || "Chief Engineer",
image: formBlogImage || "https://images.unsplash.com/photo-1504384308090-c894fdcc538d?auto=format&fit=crop&w=1200&q=80",
trTitle: formBlogTrTitle,
trExcerpt: formBlogTrExcerpt,
trReadingTime: formBlogTrReadingTime || "5 dk okuma",
trCategory: formBlogTrCategory || "Teknoloji",
trTags: formBlogTrTags.split(",").map(t => t.trim()).filter(Boolean),
trContent: formBlogTrContent || "## Yeni Teknik Blok Başlığı\nİçerik buraya gelecektir.",
enTitle: formBlogEnTitle || formBlogTrTitle,
enExcerpt: formBlogEnExcerpt || formBlogTrExcerpt,
enReadingTime: formBlogEnReadingTime || "5 min read",
enCategory: formBlogEnCategory || "Technology",
enTags: formBlogEnTags.split(",").map(t => t.trim()).filter(Boolean),
enContent: formBlogEnContent || "## New Technical Article\nContent goes here.",
};
const res = await saveBlogPost(blogPostDataToSave);
if (res.success && res.post) {
const mappedPost: BlogPost = {
id: res.post.id,
slug: res.post.slug,
date: res.post.date,
author: res.post.author,
authorRole: res.post.authorRole,
image: res.post.image,
tr: {
title: res.post.trTitle,
excerpt: res.post.trExcerpt,
readingTime: res.post.trReadingTime,
category: res.post.trCategory,
tags: res.post.trTags,
content: res.post.trContent,
},
en: {
title: res.post.enTitle,
excerpt: res.post.enExcerpt,
readingTime: res.post.enReadingTime,
category: res.post.enCategory,
tags: res.post.enTags,
content: res.post.enContent,
}
};
if (isAddingNewPost) {
setPosts([...posts, mappedPost]);
showToast(`[ BLOG YAZISI EKLEDİ // ${mappedPost.tr.title.toUpperCase()} ]`, "success");
setIsAddingNewPost(false);
} else {
setPosts(posts.map(p => p.id === editingPost?.id ? mappedPost : p));
showToast(`[ BLOG YAZISI GÜNCELLEDİ // ${mappedPost.tr.title.toUpperCase()} ]`, "success");
setEditingPost(null);
}
} else {
showToast(`Hata: ${res.error}`, "alert");
}
};
// Delete Blog Post
const handleDeletePost = async (id: number, title: string) => {
if (confirm(`"${title}" blog yazısını silmek istediğinize emin misiniz?`)) {
const res = await deleteBlogPost(id);
if (res.success) {
setPosts(posts.filter(p => p.id !== id));
showToast(`[ BLOG YAZISI SİLİNDİ // ${title.toUpperCase()} ]`, "alert");
} else {
showToast(`Hata: ${res.error}`, "alert");
}
}
};
// ── PARTNER CRUD ACTIONS ──
const handleStartEditPartner = (p: PartnerData) => {
setEditingPartner(p);
setIsAddingNewPartner(false);
setFormPartnerName(p.name);
setFormPartnerTag(p.tag);
setFormPartnerMono(p.mono);
setFormPartnerYear(p.year);
setFormPartnerDesc(p.desc);
};
const handleStartAddPartner = () => {
setEditingPartner(null);
setIsAddingNewPartner(true);
setFormPartnerName("");
setFormPartnerTag("");
setFormPartnerMono("");
setFormPartnerYear("2026");
setFormPartnerDesc("");
};
const handleSavePartner = async (e: React.FormEvent) => {
e.preventDefault();
if (!formPartnerName.trim() || !formPartnerMono.trim()) {
showToast("Partner ismi ve monogramı zorunludur!", "alert");
return;
}
const partnerDataToSave = {
id: editingPartner?.id,
name: formPartnerName.trim(),
tag: formPartnerTag.trim() || "Web3",
mono: formPartnerMono.trim().toUpperCase(),
year: formPartnerYear.trim() || "2026",
desc: formPartnerDesc.trim(),
};
const res = await savePartner(partnerDataToSave);
if (res.success && res.partner) {
if (isAddingNewPartner) {
setPartners([...partners, { ...partnerDataToSave, id: res.partner.id }]);
showToast(`[ YENİ PARTNER YARATILDI // ${formPartnerName.toUpperCase()} ]`, "success");
setIsAddingNewPartner(false);
} else {
const updatedList = partners.map(p => {
if (p.id === editingPartner?.id) {
return {
...p,
...partnerDataToSave,
};
}
return p;
});
setPartners(updatedList);
showToast(`[ PARTNER BAŞARIYLA DÜZENLENDİ // ${formPartnerName.toUpperCase()} ]`, "success");
setEditingPartner(null);
}
} else {
showToast(`Hata: ${res.error}`, "alert");
}
};
const handleDeletePartner = async (id: number, name: string) => {
if (confirm(`"${name}" iş ortağını silmek istediğinize emin misiniz?`)) {
const res = await deletePartner(id);
if (res.success) {
setPartners(partners.filter(p => p.id !== id));
showToast(`[ PARTNER SİLİNDİ // ${name.toUpperCase()} ]`, "alert");
} else {
showToast(`Hata: ${res.error}`, "alert");
}
}
};
// Save Settings Form
const handleSaveSettings = (e: React.FormEvent) => {
e.preventDefault();
showToast("[ SİTE AYARLARI BAŞARIYLA KAYDEDİLDİ VE YENİLENDİ ]", "success");
};
// Logout Handler
const handleLogout = async () => {
if (confirm("Sistemden çıkış yapmak istediğinize emin misiniz?")) {
const res = await adminLogoutAction();
if (res.success) {
window.location.href = `/${lang}/admin/login`;
} else {
showToast("Çıkış yapılırken bir hata oluştu!", "alert");
}
}
};
// Filters
const filteredProjects = projects.filter(p =>
p.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
p.tag.toLowerCase().includes(searchQuery.toLowerCase())
);
const filteredPosts = posts.filter(post =>
post.tr.title.toLowerCase().includes(blogSearchQuery.toLowerCase()) ||
post.author.toLowerCase().includes(blogSearchQuery.toLowerCase()) ||
post.tr.category.toLowerCase().includes(blogSearchQuery.toLowerCase())
);
const filteredPartners = partners.filter(p =>
p.name.toLowerCase().includes(partnerSearchQuery.toLowerCase()) ||
p.tag.toLowerCase().includes(partnerSearchQuery.toLowerCase()) ||
p.mono.toLowerCase().includes(partnerSearchQuery.toLowerCase())
);
return (
<div className="bg-[#F4F0E8] text-[#0A0A0A] font-body min-h-screen relative selection:bg-[#FFE600] selection:text-[#0A0A0A]">
<Header lang={lang} dict={dict.nav} />
<div className="pt-28 pb-24 px-6 max-w-7xl mx-auto flex flex-col lg:flex-row gap-8">
{/* LEFT NAV PANEL - Brutalist Sidebar */}
<aside className="lg:w-1/4 flex flex-col gap-4">
<div className="border border-[#C8C2B8] bg-[#EDE8E0] p-6 relative overflow-hidden">
<div className="font-mono text-[9px] tracking-[0.25em] uppercase text-[#A0998E] mb-2">[ SİSTEM YETKİSİ ]</div>
<h2 className="font-display font-black text-xl uppercase tracking-tight text-[#0A0A0A] mb-1">ADMİN PORTALI</h2>
<p className="font-mono text-[9px] uppercase tracking-wider text-[#FF4500]">[ DURUM // DOĞRULANDI ]</p>
</div>
<div className="border border-[#C8C2B8] flex flex-col divide-y divide-[#C8C2B8] bg-[#F4F0E8]">
<button
onClick={() => setActiveTab("projeler")}
className={`text-left px-6 py-4 font-display font-black text-xs tracking-widest uppercase transition-all flex items-center justify-between cursor-pointer ${
activeTab === "projeler"
? "bg-[#0A0A0A] text-[#F4F0E8] border-l-4 border-[#FFE600]"
: "hover:bg-[#EDE8E0] text-[#6A6460] hover:text-[#0A0A0A]"
}`}
>
<span>📁 PROJELERİ YÖNET</span>
<span className="font-mono text-[9px]">{projects.length} AKTİF</span>
</button>
<button
onClick={() => setActiveTab("blog")}
className={`text-left px-6 py-4 font-display font-black text-xs tracking-widest uppercase transition-all flex items-center justify-between cursor-pointer ${
activeTab === "blog"
? "bg-[#0A0A0A] text-[#F4F0E8] border-l-4 border-[#FFE600]"
: "hover:bg-[#EDE8E0] text-[#6A6460] hover:text-[#0A0A0A]"
}`}
>
<span>📝 BLOG YAZILARI</span>
<span className="font-mono text-[9px]">{posts.length} YAZI</span>
</button>
<button
onClick={() => setActiveTab("partnerler")}
className={`text-left px-6 py-4 font-display font-black text-xs tracking-widest uppercase transition-all flex items-center justify-between cursor-pointer ${
activeTab === "partnerler"
? "bg-[#0A0A0A] text-[#F4F0E8] border-l-4 border-[#FFE600]"
: "hover:bg-[#EDE8E0] text-[#6A6460] hover:text-[#0A0A0A]"
}`}
>
<span>🤝 PARTNERLER</span>
<span className="font-mono text-[9px]">{partners.length} ORTAK</span>
</button>
<button
onClick={() => setActiveTab("ayarlar")}
className={`text-left px-6 py-4 font-display font-black text-xs tracking-widest uppercase transition-all flex items-center justify-between cursor-pointer ${
activeTab === "ayarlar"
? "bg-[#0A0A0A] text-[#F4F0E8] border-l-4 border-[#FFE600]"
: "hover:bg-[#EDE8E0] text-[#6A6460] hover:text-[#0A0A0A]"
}`}
>
<span>⚙️ SİTE AYARLARI</span>
<span className="font-mono text-[9px]">GÜNCEL</span>
</button>
</div>
<Link
href={`/${lang}`}
className="border border-[#0A0A0A] hover:bg-[#0A0A0A] hover:text-[#F4F0E8] text-center py-3.5 font-display font-black text-[10px] tracking-widest uppercase transition-colors"
>
SİTEYE GERİ DÖN
</Link>
<button
onClick={handleLogout}
className="border border-[#FF4500] hover:bg-[#FF4500] hover:text-white text-center py-3.5 font-display font-black text-[10px] tracking-widest uppercase transition-colors cursor-pointer"
>
SİSTEMDEN ÇIK
</button>
</aside>
{/* RIGHT MAIN PANEL - Dashboard workspace */}
<main className="flex-grow lg:w-3/4">
<AnimatePresence mode="wait">
{/* TAB 1: PROJELER */}
{activeTab === "projeler" && (
<motion.div
key="projeler-tab"
initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -15 }}
transition={{ duration: 0.4, ease: expo }}
className="space-y-6"
>
<div className="border border-[#C8C2B8] p-4 bg-[#EDE8E0] flex flex-col sm:flex-row gap-4 items-stretch sm:items-center justify-between">
<div className="relative flex-grow max-w-md">
<input
type="text"
placeholder="Projelerde ara..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full font-mono text-[11px] bg-[#F4F0E8] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-4 py-3 placeholder-[#A0998E] text-[#0A0A0A] transition-colors"
/>
</div>
<button
onClick={handleStartAdd}
className="btn-brutal btn-brutal-yellow font-display font-black text-[11px] tracking-widest uppercase px-6 py-3 cursor-pointer shrink-0"
>
+ YENİ PROJE EKLE
</button>
</div>
<div className="flex flex-col gap-4">
{filteredProjects.map((p) => (
<div
key={p.num}
className="border border-[#C8C2B8] hover:border-[#0A0A0A] bg-[#F4F0E8] p-6 flex flex-col md:flex-row md:items-center justify-between gap-6 transition-all group relative overflow-hidden"
>
<div className="absolute top-0 bottom-0 left-0 w-1 bg-[#FFE600]" />
<div className="space-y-2 pl-2">
<div className="flex items-center gap-3">
<span className="font-mono text-[10px] tracking-wider text-[#A0998E] border border-[#C8C2B8] px-2 py-0.5 uppercase">
PROJE // 0{p.num}
</span>
<span className="font-mono text-[9px] text-[#FF4500] uppercase tracking-widest font-bold">
{p.tag}
</span>
</div>
<h3 className="font-display font-black text-2xl uppercase tracking-tight text-[#0A0A0A]">
{p.title}
</h3>
<div className="flex flex-wrap gap-1.5 pt-1">
{p.tech.map((t) => (
<span key={t} className="font-mono text-[9px] uppercase bg-[#EDE8E0] px-2 py-0.5 border border-[#C8C2B8]">
{t}
</span>
))}
</div>
</div>
<div className="flex items-center gap-2 shrink-0 md:self-center">
<button
onClick={() => handleStartEdit(p)}
className="border border-[#C8C2B8] hover:border-[#0A0A0A] hover:bg-[#0A0A0A] hover:text-[#FFE600] px-4 py-2.5 font-display font-black text-[10px] tracking-wider uppercase transition-all cursor-pointer bg-[#F4F0E8]"
>
DÜZENLE
</button>
<button
onClick={() => handleDeleteProject(p.id!, p.title)}
className="border border-[#FF4500] text-[#FF4500] hover:bg-[#FF4500] hover:text-white px-4 py-2.5 font-display font-black text-[10px] tracking-wider uppercase transition-all cursor-pointer bg-[#F4F0E8]"
>
SİL
</button>
</div>
</div>
))}
{filteredProjects.length === 0 && (
<div className="border border-dashed border-[#C8C2B8] py-16 text-center">
<p className="font-mono text-xs uppercase text-[#A0998E]">[ HİÇBİR PROJE BULUNAMADI ]</p>
</div>
)}
</div>
</motion.div>
)}
{/* TAB 2: BLOG YAZILARI YÖNETİMİ */}
{activeTab === "blog" && (
<motion.div
key="blog-tab"
initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -15 }}
transition={{ duration: 0.4, ease: expo }}
className="space-y-6"
>
<div className="border border-[#C8C2B8] p-4 bg-[#EDE8E0] flex flex-col sm:flex-row gap-4 items-stretch sm:items-center justify-between">
<div className="relative flex-grow max-w-md">
<input
type="text"
placeholder="Başlık, yazar veya kategori ara..."
value={blogSearchQuery}
onChange={(e) => setBlogSearchQuery(e.target.value)}
className="w-full font-mono text-[11px] bg-[#F4F0E8] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-4 py-3 placeholder-[#A0998E] text-[#0A0A0A] transition-colors"
/>
</div>
<button
onClick={handleStartAddPost}
className="btn-brutal btn-brutal-yellow font-display font-black text-[11px] tracking-widest uppercase px-6 py-3 cursor-pointer shrink-0"
>
+ YENİ YAZI EKLE
</button>
</div>
<div className="flex flex-col gap-4">
{filteredPosts.map((post) => (
<div
key={post.slug}
className="border border-[#C8C2B8] hover:border-[#0A0A0A] bg-[#F4F0E8] p-6 flex flex-col md:flex-row md:items-center justify-between gap-6 transition-all group relative overflow-hidden"
>
<div className="absolute top-0 bottom-0 left-0 w-1 bg-[#FF4500]" />
<div className="space-y-2 pl-2">
<div className="flex items-center gap-3">
<span className="font-mono text-[9px] tracking-wider text-[#A0998E] border border-[#C8C2B8] px-2 py-0.5 uppercase">
SLUG: {post.slug}
</span>
<span className="font-mono text-[9px] text-[#00CC77] uppercase tracking-widest font-bold">
{post.tr.category}
</span>
</div>
<h3 className="font-display font-black text-xl uppercase tracking-tight text-[#0A0A0A]">
{post.tr.title}
</h3>
<p className="text-[11px] text-[#A0998E] font-mono uppercase">
Yazar: {post.author} ({post.authorRole}) Tarih: {post.date}
</p>
</div>
<div className="flex items-center gap-2 shrink-0 md:self-center">
<button
onClick={() => handleStartEditPost(post)}
className="border border-[#C8C2B8] hover:border-[#0A0A0A] hover:bg-[#0A0A0A] hover:text-[#FFE600] px-4 py-2.5 font-display font-black text-[10px] tracking-wider uppercase transition-all cursor-pointer bg-[#F4F0E8]"
>
DÜZENLE
</button>
<button
onClick={() => handleDeletePost(post.id!, post.tr.title)}
className="border border-[#FF4500] text-[#FF4500] hover:bg-[#FF4500] hover:text-white px-4 py-2.5 font-display font-black text-[10px] tracking-wider uppercase transition-all cursor-pointer bg-[#F4F0E8]"
>
SİL
</button>
</div>
</div>
))}
{filteredPosts.length === 0 && (
<div className="border border-dashed border-[#C8C2B8] py-16 text-center">
<p className="font-mono text-xs uppercase text-[#A0998E]">[ HİÇBİR BLOG YAZISI BULUNAMADI ]</p>
</div>
)}
</div>
</motion.div>
)}
{/* TAB 2.5: PARTNERLER YÖNETİMİ */}
{activeTab === "partnerler" && (
<motion.div
key="partners-tab"
initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -15 }}
transition={{ duration: 0.4, ease: expo }}
className="space-y-6"
>
<div className="border border-[#C8C2B8] p-4 bg-[#EDE8E0] flex flex-col sm:flex-row gap-4 items-stretch sm:items-center justify-between">
<div className="relative flex-grow max-w-md">
<input
type="text"
placeholder="Partnerlerde ara..."
value={partnerSearchQuery}
onChange={(e) => setPartnerSearchQuery(e.target.value)}
className="w-full font-mono text-[11px] bg-[#F4F0E8] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-4 py-3 placeholder-[#A0998E] text-[#0A0A0A] transition-colors"
/>
</div>
<button
onClick={handleStartAddPartner}
className="btn-brutal btn-brutal-yellow font-display font-black text-[11px] tracking-widest uppercase px-6 py-3 cursor-pointer shrink-0"
>
+ YENİ PARTNER EKLE
</button>
</div>
<div className="flex flex-col gap-4">
{filteredPartners.map((p) => (
<div
key={p.id}
className="border border-[#C8C2B8] hover:border-[#0A0A0A] bg-[#F4F0E8] p-6 flex flex-col md:flex-row md:items-center justify-between gap-6 transition-all group relative overflow-hidden"
>
<div className="absolute top-0 bottom-0 left-0 w-1 bg-[#FFE600]" />
<div className="space-y-2 pl-2">
<div className="flex items-center gap-3">
<span className="font-mono text-[10px] tracking-wider text-[#A0998E] border border-[#C8C2B8] px-2 py-0.5 uppercase">
MONOGRAM: {p.mono}
</span>
<span className="font-mono text-[9px] text-[#FF4500] uppercase tracking-widest font-bold">
{p.tag}
</span>
<span className="font-mono text-[9px] text-[#A0998E] uppercase tracking-widest">
YIL: {p.year}
</span>
</div>
<h3 className="font-display font-black text-2xl uppercase tracking-tight text-[#0A0A0A]">
{p.name}
</h3>
<p className="text-[12px] text-[#6A6460] font-sans">
{p.desc}
</p>
</div>
<div className="flex items-center gap-2 shrink-0 md:self-center">
<button
onClick={() => handleStartEditPartner(p)}
className="border border-[#C8C2B8] hover:border-[#0A0A0A] hover:bg-[#0A0A0A] hover:text-[#FFE600] px-4 py-2.5 font-display font-black text-[10px] tracking-wider uppercase transition-all cursor-pointer bg-[#F4F0E8]"
>
DÜZENLE
</button>
<button
onClick={() => handleDeletePartner(p.id!, p.name)}
className="border border-[#FF4500] text-[#FF4500] hover:bg-[#FF4500] hover:text-white px-4 py-2.5 font-display font-black text-[10px] tracking-wider uppercase transition-all cursor-pointer bg-[#F4F0E8]"
>
SİL
</button>
</div>
</div>
))}
{filteredPartners.length === 0 && (
<div className="border border-dashed border-[#C8C2B8] py-16 text-center">
<p className="font-mono text-xs uppercase text-[#A0998E]">[ HİÇBİR PARTNER BULUNAMADI ]</p>
</div>
)}
</div>
</motion.div>
)}
{/* TAB 3: SITE AYARLARI */}
{activeTab === "ayarlar" && (
<motion.div
key="ayarlar-tab"
initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -15 }}
transition={{ duration: 0.4, ease: expo }}
className="border border-[#C8C2B8] bg-[#F4F0E8] p-8"
>
<div className="border-b border-[#C8C2B8] pb-6 mb-8">
<h3 className="font-display font-black text-2xl uppercase tracking-tight text-[#0A0A0A]">⚙️ SİTE GENEL YAPILANDIRMASI</h3>
<p className="text-[#6A6460] text-[13px] mt-1">Görsel kimlik, başlıklar ve iletişim kanallarının yönetimi.</p>
</div>
<form onSubmit={handleSaveSettings} className="space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<label className="font-mono text-[10px] tracking-wider uppercase text-[#A0998E] block">MARKA ADI (BRAND NAME)</label>
<input
type="text"
value={brandName}
onChange={(e) => setBrandName(e.target.value)}
className="w-full font-mono text-[12px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-4 py-3 text-[#0A0A0A]"
/>
</div>
<div className="space-y-2">
<label className="font-mono text-[10px] tracking-wider uppercase text-[#A0998E] block">MARKA ALT BAŞLIĞI (BRAND SUB)</label>
<input
type="text"
value={brandSub}
onChange={(e) => setBrandSub(e.target.value)}
className="w-full font-mono text-[12px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-4 py-3 text-[#0A0A0A]"
/>
</div>
</div>
<div className="space-y-2">
<label className="font-mono text-[10px] tracking-wider uppercase text-[#A0998E] block">KAHRAMAN BÖLÜMÜ YAZISI (HERO BADGE)</label>
<input
type="text"
value={heroBadge}
onChange={(e) => setHeroBadge(e.target.value)}
className="w-full font-mono text-[12px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-4 py-3 text-[#0A0A0A]"
/>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<label className="font-mono text-[10px] tracking-wider uppercase text-[#A0998E] block">ANA BAŞLIK SATIRI 1</label>
<input
type="text"
value={heroTitle1}
onChange={(e) => setHeroTitle1(e.target.value)}
className="w-full font-mono text-[12px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-4 py-3 text-[#0A0A0A]"
/>
</div>
<div className="space-y-2">
<label className="font-mono text-[10px] tracking-wider uppercase text-[#A0998E] block">ANA BAŞLIK SATIRI 2</label>
<input
type="text"
value={heroTitle2}
onChange={(e) => setHeroTitle2(e.target.value)}
className="w-full font-mono text-[12px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-4 py-3 text-[#0A0A0A]"
/>
</div>
</div>
<div className="space-y-2">
<label className="font-mono text-[10px] tracking-wider uppercase text-[#A0998E] block">HERO AÇIKLAMA METNİ</label>
<textarea
value={heroDesc}
rows={3}
onChange={(e) => setHeroDesc(e.target.value)}
className="w-full font-mono text-[12px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-4 py-3 text-[#0A0A0A] resize-y"
/>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 border-t border-[#C8C2B8] pt-6">
<div className="space-y-2">
<label className="font-mono text-[10px] tracking-wider uppercase text-[#A0998E] block">TELEMETRİ İLETİŞİM E-POSTASI</label>
<input
type="email"
value={telemetryEmail}
onChange={(e) => setTelemetryEmail(e.target.value)}
className="w-full font-mono text-[12px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-4 py-3 text-[#0A0A0A]"
/>
</div>
<div className="space-y-2">
<label className="font-mono text-[10px] tracking-wider uppercase text-[#A0998E] block">MÜHENDİSLİK OPERASYONEL MERKEZİ</label>
<input
type="text"
value={telemetryHub}
onChange={(e) => setTelemetryHub(e.target.value)}
className="w-full font-mono text-[12px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-4 py-3 text-[#0A0A0A]"
/>
</div>
</div>
<div className="pt-4 border-t border-[#C8C2B8] flex justify-end">
<button
type="submit"
className="btn-brutal btn-brutal-yellow font-display font-black text-[11px] tracking-widest uppercase px-8 py-4 cursor-pointer"
>
AYARLARI KAYDET VE SİTEYİ GÜNCELLE
</button>
</div>
</form>
</motion.div>
)}
</AnimatePresence>
</main>
</div>
{/* CRUD ADD/EDIT MODAL OVERLAY (FOR PROJECTS) */}
<AnimatePresence>
{(editingProject || isAddingNew) && (
<div className="fixed inset-0 z-[100] flex items-center justify-center bg-black/60 backdrop-blur-sm px-4 py-8 overflow-y-auto">
<motion.div
className="bg-[#F4F0E8] border-2 border-[#0A0A0A] p-8 max-w-3xl w-full max-h-[85vh] overflow-y-auto relative shadow-[8px 8px_0px_0px_#0A0A0A]"
initial={{ scale: 0.95, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.95, opacity: 0 }}
transition={{ duration: 0.3, ease: expo }}
>
<button
onClick={() => {
setEditingProject(null);
setIsAddingNew(false);
}}
className="absolute top-6 right-6 font-mono text-xs text-[#A0998E] hover:text-[#0A0A0A] border border-[#C8C2B8] hover:border-[#0A0A0A] w-8 h-8 flex items-center justify-center cursor-pointer bg-[#F4F0E8] transition-colors"
>
[X]
</button>
<h3 className="font-display font-black text-2xl uppercase tracking-tight text-[#0A0A0A] mb-6 pb-3 border-b border-[#C8C2B8]">
{isAddingNew ? "📂 YENİ PROJE EKLEME FORMU" : `⚙️ PROJE DÜZENLEME // 0${editingProject?.num}`}
</h3>
<form onSubmit={handleSaveProject} className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Proje Başlığı</label>
<input
type="text"
required
value={formTitle}
onChange={(e) => setFormTitle(e.target.value)}
placeholder="Örn: FinanceAI Paneli"
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Kategori / Tag</label>
<input
type="text"
required
value={formTag}
onChange={(e) => setFormTag(e.target.value)}
placeholder="Örn: YZ · Finans"
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Proje Özet Açıklaması</label>
<textarea
rows={2}
required
value={formDesc}
onChange={(e) => setFormDesc(e.target.value)}
placeholder="Projeyi kısaca açıklayınız..."
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A] resize-y"
/>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Performans / Güvence Metriği (Spec)</label>
<input
type="text"
required
value={formSpec}
onChange={(e) => setFormSpec(e.target.value)}
placeholder="Örn: Gerçek zamanlı akış, 10ms altı yanıt süresi."
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Yıl</label>
<input
type="text"
required
value={formYear}
onChange={(e) => setFormYear(e.target.value)}
placeholder="Örn: 2024"
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Müşteri</label>
<input
type="text"
required
value={formClient}
onChange={(e) => setFormClient(e.target.value)}
placeholder="Örn: Acme Fintech Ltd."
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Geliştirme Süresi</label>
<input
type="text"
required
value={formDuration}
onChange={(e) => setFormDuration(e.target.value)}
placeholder="Örn: 14 hafta"
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Teknoloji Yığını (Virgülle Ayırın)</label>
<input
type="text"
required
value={formTechString}
onChange={(e) => setFormTechString(e.target.value)}
placeholder="Next.js, Python, TensorFlow, Redis, Kafka"
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Kapak Görseli URL Adresi</label>
<div className="flex gap-2">
<input
type="text"
value={formImage}
onChange={(e) => setFormImage(e.target.value)}
placeholder="https://images.unsplash.com/..."
className="flex-grow font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
<label className="border border-[#0A0A0A] px-3 flex items-center justify-center font-display font-black text-[9px] uppercase tracking-wider transition-colors cursor-pointer bg-[#F4F0E8] hover:bg-[#EDE8E0] shrink-0">
{uploadingImage ? "YÜKLENİYOR..." : "YÜKLE"}
<input
type="file"
accept="image/*"
className="hidden"
disabled={uploadingImage}
onChange={async (e) => {
const file = e.target.files?.[0];
if (!file) return;
setUploadingImage(true);
try {
const url = await handleFileUpload(file);
setFormImage(url);
} catch (err) {
showToast("Resim yüklenemedi", "alert");
} finally {
setUploadingImage(false);
}
}}
/>
</label>
</div>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Website URL (Opsiyonel)</label>
<input
type="text"
value={formWebsite}
onChange={(e) => setFormWebsite(e.target.value)}
placeholder="https://example.com"
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Karşılaşılan Problem (Challenge)</label>
<textarea
rows={3}
required
value={formChallenge}
onChange={(e) => setFormChallenge(e.target.value)}
className="w-full font-mono text-[10px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A] resize-y"
/>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Mühendislik Çözümümüz (Solution)</label>
<textarea
rows={3}
required
value={formSolution}
onChange={(e) => setFormSolution(e.target.value)}
className="w-full font-mono text-[10px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A] resize-y"
/>
</div>
</div>
<div className="space-y-2 pt-2 border-t border-[#C8C2B8]">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Elde Edilen Sonuçlar</label>
<div className="flex flex-col gap-2 mb-2 max-h-24 overflow-y-auto border border-[#C8C2B8] p-2 bg-[#EDE8E0]">
{formResults.map((item, idx) => (
<div key={idx} className="flex items-center justify-between gap-3 bg-[#F4F0E8] border border-[#C8C2B8] px-3 py-1">
<span className="font-display font-bold text-[9px] uppercase text-[#0A0A0A] truncate">{item}</span>
<button
type="button"
onClick={() => handleRemoveResultItem(idx)}
className="font-mono text-[8px] text-[#FF4500] cursor-pointer"
>
[ SİL ]
</button>
</div>
))}
</div>
<div className="flex gap-2">
<input
type="text"
value={newResultItem}
onChange={(e) => setNewResultItem(e.target.value)}
className="flex-grow font-mono text-[9px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
<button
type="button"
onClick={handleAddResultItem}
className="border border-[#0A0A0A] px-4 font-display font-black text-[9px] uppercase tracking-wider transition-colors cursor-pointer bg-[#F4F0E8]"
>
[ EKLE ]
</button>
</div>
</div>
<div className="space-y-2 pt-2 border-t border-[#C8C2B8]">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Galeri Görselleri (Ekran Görüntüleri)</label>
<div className="flex flex-col gap-2 mb-2 max-h-24 overflow-y-auto border border-[#C8C2B8] p-2 bg-[#EDE8E0]">
{formGallery.map((item, idx) => (
<div key={idx} className="flex items-center justify-between gap-3 bg-[#F4F0E8] border border-[#C8C2B8] px-3 py-1">
<span className="font-display font-bold text-[9px] uppercase text-[#0A0A0A] truncate">{item}</span>
<button
type="button"
onClick={() => handleRemoveGalleryItem(idx)}
className="font-mono text-[8px] text-[#FF4500] cursor-pointer"
>
[ SİL ]
</button>
</div>
))}
</div>
<div className="flex gap-2">
<input
type="text"
value={newGalleryItem}
onChange={(e) => setNewGalleryItem(e.target.value)}
placeholder="https://images.unsplash.com/..."
className="flex-grow font-mono text-[9px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
<label className="border border-[#0A0A0A] px-3 flex items-center justify-center font-display font-black text-[9px] uppercase tracking-wider transition-colors cursor-pointer bg-[#F4F0E8] hover:bg-[#EDE8E0] shrink-0">
{uploadingGallery ? "YÜKLENİYOR..." : "RESİM YÜKLE"}
<input
type="file"
accept="image/*"
className="hidden"
disabled={uploadingGallery}
onChange={async (e) => {
const file = e.target.files?.[0];
if (!file) return;
setUploadingGallery(true);
try {
const url = await handleFileUpload(file);
setFormGallery(prev => [...prev, url]);
} catch (err) {
showToast("Resim yüklenemedi", "alert");
} finally {
setUploadingGallery(false);
}
}}
/>
</label>
<button
type="button"
onClick={handleAddGalleryItem}
className="border border-[#0A0A0A] px-4 font-display font-black text-[9px] uppercase tracking-wider transition-colors cursor-pointer bg-[#F4F0E8] shrink-0"
>
[ EKLE ]
</button>
</div>
</div>
<div className="pt-4 border-t border-[#C8C2B8] flex justify-end gap-2">
<button
type="button"
onClick={() => {
setEditingProject(null);
setIsAddingNew(false);
}}
className="border border-[#C8C2B8] hover:border-[#0A0A0A] px-6 py-3 font-display font-black text-[10px] tracking-wider uppercase transition-colors cursor-pointer bg-[#F4F0E8]"
>
İPTAL ET
</button>
<button
type="submit"
className="btn-brutal btn-brutal-yellow font-display font-black text-[10px] tracking-widest uppercase px-6 py-3 cursor-pointer"
>
PROJEYİ KAYDET VE UYGULA
</button>
</div>
</form>
</motion.div>
</div>
)}
</AnimatePresence>
{/* CRUD ADD/EDIT MODAL OVERLAY (FOR BLOG POSTS) */}
<AnimatePresence>
{(editingPost || isAddingNewPost) && (
<div className="fixed inset-0 z-[100] flex items-center justify-center bg-black/60 backdrop-blur-sm px-4 py-8 overflow-y-auto">
<motion.div
className="bg-[#F4F0E8] border-2 border-[#0A0A0A] p-8 max-w-3xl w-full max-h-[85vh] overflow-y-auto relative shadow-[8px 8px_0px_0px_#0A0A0A]"
initial={{ scale: 0.95, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.95, opacity: 0 }}
transition={{ duration: 0.3, ease: expo }}
>
<button
onClick={() => {
setEditingPost(null);
setIsAddingNewPost(false);
}}
className="absolute top-6 right-6 font-mono text-xs text-[#A0998E] hover:text-[#0A0A0A] border border-[#C8C2B8] hover:border-[#0A0A0A] w-8 h-8 flex items-center justify-center cursor-pointer bg-[#F4F0E8] transition-colors"
>
[X]
</button>
<h3 className="font-display font-black text-2xl uppercase tracking-tight text-[#0A0A0A] mb-4 pb-3 border-b border-[#C8C2B8]">
{isAddingNewPost ? "📝 YENİ BLOG YAZISI EKLE" : `⚙️ BLOG YAZISI DÜZENLEME`}
</h3>
{/* Form Sub-Tabs Navigation */}
<div className="flex border border-[#C8C2B8] bg-[#EDE8E0] mb-6">
<button
type="button"
onClick={() => setBlogFormSubTab("genel")}
className={`flex-1 py-2.5 font-display font-black text-[10px] tracking-wider uppercase transition-colors cursor-pointer ${
blogFormSubTab === "genel" ? "bg-[#0A0A0A] text-[#F4F0E8]" : "hover:bg-[#F4F0E8] text-[#6A6460]"
}`}
>
Genel Bilgiler
</button>
<button
type="button"
onClick={() => setBlogFormSubTab("tr")}
className={`flex-1 py-2.5 font-display font-black text-[10px] tracking-wider uppercase transition-colors cursor-pointer ${
blogFormSubTab === "tr" ? "bg-[#0A0A0A] text-[#F4F0E8]" : "hover:bg-[#F4F0E8] text-[#6A6460]"
}`}
>
Türkçe İçerik (TR)
</button>
<button
type="button"
onClick={() => setBlogFormSubTab("en")}
className={`flex-1 py-2.5 font-display font-black text-[10px] tracking-wider uppercase transition-colors cursor-pointer ${
blogFormSubTab === "en" ? "bg-[#0A0A0A] text-[#F4F0E8]" : "hover:bg-[#F4F0E8] text-[#6A6460]"
}`}
>
English Content (EN)
</button>
</div>
<form onSubmit={handleSavePost} className="space-y-4">
{/* SUB TAB: GENEL BİLGİLER */}
{blogFormSubTab === "genel" && (
<div className="space-y-4 animate-fadeIn">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Yazı Slug Değeri (URL)</label>
<input
type="text"
value={formBlogSlug}
onChange={(e) => setFormBlogSlug(e.target.value)}
placeholder="Örn: real-time-anomaly-detection-ai"
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Yayın Tarihi</label>
<input
type="date"
required
value={formBlogDate}
onChange={(e) => setFormBlogDate(e.target.value)}
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Yazar Adı Soyadı</label>
<input
type="text"
required
value={formBlogAuthor}
onChange={(e) => setFormBlogAuthor(e.target.value)}
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Yazar Rolü</label>
<input
type="text"
required
value={formBlogAuthorRole}
onChange={(e) => setFormBlogAuthorRole(e.target.value)}
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Kapak Görseli URL Adresi</label>
<input
type="text"
value={formBlogImage}
onChange={(e) => setFormBlogImage(e.target.value)}
placeholder="https://images.unsplash.com/..."
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
</div>
)}
{/* SUB TAB: TÜRKÇE İÇERİK */}
{blogFormSubTab === "tr" && (
<div className="space-y-4 animate-fadeIn">
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="md:col-span-2 space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Yazı Başlığı (TR)</label>
<input
type="text"
required={blogFormSubTab === "tr"}
value={formBlogTrTitle}
onChange={(e) => setFormBlogTrTitle(e.target.value)}
placeholder="Türkçe başlık giriniz..."
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Okuma Süresi (TR)</label>
<input
type="text"
value={formBlogTrReadingTime}
onChange={(e) => setFormBlogTrReadingTime(e.target.value)}
placeholder="Örn: 5 dk okuma"
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Kategori (TR)</label>
<input
type="text"
value={formBlogTrCategory}
onChange={(e) => setFormBlogTrCategory(e.target.value)}
placeholder="Örn: YZ · Finans"
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Etiketler (Virgülle Ayırın)</label>
<input
type="text"
value={formBlogTrTags}
onChange={(e) => setFormBlogTrTags(e.target.value)}
placeholder="AI, Fintech, Web3"
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Özet Açıklama (TR)</label>
<textarea
rows={2}
value={formBlogTrExcerpt}
onChange={(e) => setFormBlogTrExcerpt(e.target.value)}
placeholder="Kısa özet giriniz..."
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A] resize-y"
/>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Makale Metni Markdown (TR)</label>
<textarea
rows={6}
value={formBlogTrContent}
onChange={(e) => setFormBlogTrContent(e.target.value)}
placeholder="## Başlıklar ve paragraflar..."
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A] resize-y"
/>
</div>
</div>
)}
{/* SUB TAB: ENGLISH CONTENT */}
{blogFormSubTab === "en" && (
<div className="space-y-4 animate-fadeIn">
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="md:col-span-2 space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Article Title (EN)</label>
<input
type="text"
value={formBlogEnTitle}
onChange={(e) => setFormBlogEnTitle(e.target.value)}
placeholder="Enter English title..."
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Reading Time (EN)</label>
<input
type="text"
value={formBlogEnReadingTime}
onChange={(e) => setFormBlogEnReadingTime(e.target.value)}
placeholder="e.g. 5 min read"
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Category (EN)</label>
<input
type="text"
value={formBlogEnCategory}
onChange={(e) => setFormBlogEnCategory(e.target.value)}
placeholder="e.g. AI · Fintech"
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Tags (Comma Separated)</label>
<input
type="text"
value={formBlogEnTags}
onChange={(e) => setFormBlogEnTags(e.target.value)}
placeholder="AI, Fintech, Web3"
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Excerpt (EN)</label>
<textarea
rows={2}
value={formBlogEnExcerpt}
onChange={(e) => setFormBlogEnExcerpt(e.target.value)}
placeholder="Enter short description..."
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A] resize-y"
/>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Article Body Markdown (EN)</label>
<textarea
rows={6}
value={formBlogEnContent}
onChange={(e) => setFormBlogEnContent(e.target.value)}
placeholder="## Headers and paragraphs..."
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A] resize-y"
/>
</div>
</div>
)}
{/* Sub-tab navigation helpers */}
<div className="flex gap-2 font-mono text-[9px] text-[#A0998E] py-2">
<span>* Lütfen formu onaylamadan önce Türkçe ve İngilizce tüm sekmeleri kontrol edin.</span>
</div>
{/* Actions */}
<div className="pt-4 border-t border-[#C8C2B8] flex justify-end gap-2">
<button
type="button"
onClick={() => {
setEditingPost(null);
setIsAddingNewPost(false);
}}
className="border border-[#C8C2B8] hover:border-[#0A0A0A] px-6 py-3 font-display font-black text-[10px] tracking-wider uppercase transition-colors cursor-pointer bg-[#F4F0E8]"
>
İPTAL ET
</button>
<button
type="submit"
className="btn-brutal btn-brutal-yellow font-display font-black text-[10px] tracking-widest uppercase px-6 py-3 cursor-pointer"
>
YAZIYI PAYLAŞ VE YAYINLA
</button>
</div>
</form>
</motion.div>
</div>
)}
</AnimatePresence>
{/* CRUD ADD/EDIT MODAL OVERLAY (FOR PARTNERS) */}
<AnimatePresence>
{(editingPartner || isAddingNewPartner) && (
<div className="fixed inset-0 z-[100] flex items-center justify-center bg-black/60 backdrop-blur-sm px-4 py-8 overflow-y-auto">
<motion.div
className="bg-[#F4F0E8] border-2 border-[#0A0A0A] p-8 max-w-xl w-full max-h-[85vh] overflow-y-auto relative shadow-[8px 8px_0px_0px_#0A0A0A]"
initial={{ scale: 0.95, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.95, opacity: 0 }}
transition={{ duration: 0.3, ease: expo }}
>
<button
onClick={() => {
setEditingPartner(null);
setIsAddingNewPartner(false);
}}
className="absolute top-6 right-6 font-mono text-xs text-[#A0998E] hover:text-[#0A0A0A] border border-[#C8C2B8] hover:border-[#0A0A0A] w-8 h-8 flex items-center justify-center cursor-pointer bg-[#F4F0E8] transition-colors"
>
[X]
</button>
<h3 className="font-display font-black text-2xl uppercase tracking-tight text-[#0A0A0A] mb-6 pb-3 border-b border-[#C8C2B8]">
{isAddingNewPartner ? "🤝 YENİ PARTNER EKLE" : `⚙️ PARTNER DÜZENLEME`}
</h3>
<form onSubmit={handleSavePartner} className="space-y-4">
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Partner İsmi</label>
<input
type="text"
required
value={formPartnerName}
onChange={(e) => setFormPartnerName(e.target.value)}
placeholder="Örn: Ayris Labs"
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Monogram (Görsel Monolog)</label>
<input
type="text"
required
value={formPartnerMono}
onChange={(e) => setFormPartnerMono(e.target.value)}
placeholder="Örn: AYL"
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Kategori / Alan</label>
<input
type="text"
required
value={formPartnerTag}
onChange={(e) => setFormPartnerTag(e.target.value)}
placeholder="Örn: Web3"
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Başlangıç Yılı</label>
<input
type="text"
required
value={formPartnerYear}
onChange={(e) => setFormPartnerYear(e.target.value)}
placeholder="Örn: 2026"
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A]"
/>
</div>
</div>
<div className="space-y-1">
<label className="font-mono text-[9px] uppercase text-[#A0998E] block">Kısa Açıklama / Biyografi</label>
<textarea
rows={4}
value={formPartnerDesc}
onChange={(e) => setFormPartnerDesc(e.target.value)}
placeholder="Partner hakkında kısa detay..."
className="w-full font-mono text-[11px] bg-[#EDE8E0] border border-[#C8C2B8] focus:border-[#0A0A0A] outline-none px-3 py-2 text-[#0A0A0A] resize-none"
/>
</div>
<div className="pt-4 border-t border-[#C8C2B8] flex justify-end gap-2">
<button
type="button"
onClick={() => {
setEditingPartner(null);
setIsAddingNewPartner(false);
}}
className="border border-[#C8C2B8] hover:border-[#0A0A0A] px-6 py-3 font-display font-black text-[10px] tracking-wider uppercase transition-colors cursor-pointer bg-[#F4F0E8]"
>
İPTAL ET
</button>
<button
type="submit"
className="btn-brutal btn-brutal-yellow font-display font-black text-[10px] tracking-widest uppercase px-6 py-3 cursor-pointer"
>
PARTNERİ KAYDET
</button>
</div>
</form>
</motion.div>
</div>
)}
</AnimatePresence>
{/* TACTILE FLOATING NOTIFICATION TOAST */}
<AnimatePresence>
{toast && (
<motion.div
className="fixed bottom-8 right-8 z-[200] border-2 border-[#0A0A0A] bg-[#FFE600] text-[#0A0A0A] font-mono text-[10px] px-6 py-4 shadow-[4px 4px_0px_0px_#0A0A0A]"
initial={{ y: 50, opacity: 0, scale: 0.9 }}
animate={{ y: 0, opacity: 1, scale: 1 }}
exit={{ y: 50, opacity: 0, scale: 0.9 }}
transition={{ duration: 0.35, ease: expo }}
>
<div className="flex items-center gap-3">
<span className="animate-pulse"></span>
<span>{toast.text}</span>
</div>
</motion.div>
)}
</AnimatePresence>
</div>
);
}