This commit is contained in:
Şahan Hasret
2025-12-14 00:33:20 +03:00
parent 2ebc63ac6a
commit a2c4fcc91a
13 changed files with 1096 additions and 57 deletions

49
package-lock.json generated
View File

@@ -8,6 +8,8 @@
"name": "my-app", "name": "my-app",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@emailjs/browser": "^4.4.1",
"@vercel/analytics": "^1.6.1",
"next": "16.0.10", "next": "16.0.10",
"react": "19.2.1", "react": "19.2.1",
"react-dom": "19.2.1" "react-dom": "19.2.1"
@@ -276,6 +278,15 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@emailjs/browser": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/@emailjs/browser/-/browser-4.4.1.tgz",
"integrity": "sha512-DGSlP9sPvyFba3to2A50kDtZ+pXVp/0rhmqs2LmbMS3I5J8FSOgLwzY2Xb4qfKlOVHh29EAutLYwe5yuEZmEFg==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@emnapi/core": { "node_modules/@emnapi/core": {
"version": "1.7.1", "version": "1.7.1",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz",
@@ -2113,6 +2124,44 @@
"win32" "win32"
] ]
}, },
"node_modules/@vercel/analytics": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.6.1.tgz",
"integrity": "sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg==",
"license": "MPL-2.0",
"peerDependencies": {
"@remix-run/react": "^2",
"@sveltejs/kit": "^1 || ^2",
"next": ">= 13",
"react": "^18 || ^19 || ^19.0.0-rc",
"svelte": ">= 4",
"vue": "^3",
"vue-router": "^4"
},
"peerDependenciesMeta": {
"@remix-run/react": {
"optional": true
},
"@sveltejs/kit": {
"optional": true
},
"next": {
"optional": true
},
"react": {
"optional": true
},
"svelte": {
"optional": true
},
"vue": {
"optional": true
},
"vue-router": {
"optional": true
}
}
},
"node_modules/acorn": { "node_modules/acorn": {
"version": "8.15.0", "version": "8.15.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",

View File

@@ -9,6 +9,8 @@
"lint": "eslint" "lint": "eslint"
}, },
"dependencies": { "dependencies": {
"@emailjs/browser": "^4.4.1",
"@vercel/analytics": "^1.6.1",
"next": "16.0.10", "next": "16.0.10",
"react": "19.2.1", "react": "19.2.1",
"react-dom": "19.2.1" "react-dom": "19.2.1"

11
public/robots.txt Normal file
View File

@@ -0,0 +1,11 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Allow: /
# Sitemap
Sitemap: https://zerosixlab.com/sitemap.xml
# Disallow admin/private areas
Disallow: /api/
Disallow: /_next/
Disallow: /static/

View File

@@ -105,3 +105,56 @@ body {
z-index: 9999; z-index: 9999;
opacity: 0.15; opacity: 0.15;
} }
/* Accessibility: Reduce motion for users who prefer it */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
.scanlines {
display: none;
}
.animate-pulse,
.animate-spin,
.animate-bounce {
animation: none !important;
}
}
/* Skip to main content link for keyboard users */
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: var(--zsl-primary);
color: black;
padding: 8px 16px;
z-index: 10000;
font-weight: bold;
transition: top 0.3s;
}
.skip-link:focus {
top: 0;
}
/* Focus visible styles for better keyboard navigation */
:focus-visible {
outline: 2px solid var(--zsl-primary);
outline-offset: 2px;
}
/* Better button and link focus states */
button:focus-visible,
a:focus-visible {
outline: 2px solid var(--zsl-primary);
outline-offset: 2px;
border-radius: 4px;
}

View File

@@ -1,5 +1,6 @@
import type { Metadata, Viewport } from "next"; import type { Metadata, Viewport } from "next";
import { Inter, Orbitron } from "next/font/google"; import { Inter, Orbitron } from "next/font/google";
import { Analytics } from '@vercel/analytics/next';
import React from 'react'; import React from 'react';
import "./globals.css"; import "./globals.css";
@@ -13,6 +14,7 @@ export const viewport: Viewport = {
}; };
export const metadata: Metadata = { export const metadata: Metadata = {
metadataBase: new URL('https://zerosixlab.com'),
title: { title: {
default: "ZeroSixLab - Geleceği Kodlayan Laboratuvar", default: "ZeroSixLab - Geleceği Kodlayan Laboratuvar",
template: "%s | ZeroSixLab" template: "%s | ZeroSixLab"
@@ -90,7 +92,13 @@ export default function RootLayout({
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
</head> </head>
<body className={`${inter.variable} ${orbitron.variable} font-sans bg-zsl-bg text-zsl-text`}> <body className={`${inter.variable} ${orbitron.variable} font-sans bg-zsl-bg text-zsl-text`}>
{children} <a href="#main-content" className="skip-link">
Ana içeriğe atla
</a>
<main id="main-content">
{children}
</main>
<Analytics />
<div className="scanlines"></div> <div className="scanlines"></div>
</body> </body>
</html> </html>

View File

@@ -1,24 +1,38 @@
"use client"; 'use client';
import React from 'react'; import React from 'react';
import Link from 'next/link'; import Link from 'next/link';
// Static positions for floating elements to avoid hydration mismatch
const FLOATING_POSITIONS = [
{ left: '10%', top: '15%', delay: '0s' },
{ left: '25%', top: '45%', delay: '0.3s' },
{ left: '45%', top: '75%', delay: '0.6s' },
{ left: '65%', top: '25%', delay: '0.9s' },
{ left: '80%', top: '55%', delay: '1.2s' },
{ left: '15%', top: '85%', delay: '1.5s' },
{ left: '55%', top: '10%', delay: '1.8s' },
{ left: '90%', top: '35%', delay: '0.2s' },
{ left: '35%', top: '65%', delay: '0.5s' },
{ left: '75%', top: '90%', delay: '0.8s' },
];
export default function NotFound() { export default function NotFound() {
return ( return (
<div className="min-h-screen bg-zsl-bg flex flex-col items-center justify-center p-6 relative overflow-hidden"> <div className="min-h-screen bg-[#0a0f1a] flex flex-col items-center justify-center p-6 relative overflow-hidden">
{/* Background Grid */} {/* Background Grid */}
<div className="absolute inset-0 cyber-grid opacity-10"></div> <div className="absolute inset-0 cyber-grid opacity-10"></div>
{/* Floating elements */} {/* Floating elements */}
<div className="absolute inset-0 overflow-hidden pointer-events-none"> <div className="absolute inset-0 overflow-hidden pointer-events-none">
{[...Array(10)].map((_, i) => ( {FLOATING_POSITIONS.map((pos, i) => (
<div <div
key={i} key={i}
className="absolute w-2 h-2 bg-zsl-primary/30 rounded-full animate-pulse" className="absolute w-2 h-2 bg-zsl-primary/30 rounded-full animate-pulse"
style={{ style={{
left: `${Math.random() * 100}%`, left: pos.left,
top: `${Math.random() * 100}%`, top: pos.top,
animationDelay: `${Math.random() * 2}s`, animationDelay: pos.delay,
}} }}
/> />
))} ))}
@@ -58,7 +72,7 @@ export default function NotFound() {
<span className="ml-2 text-zsl-muted text-xs">terminal</span> <span className="ml-2 text-zsl-muted text-xs">terminal</span>
</div> </div>
<div className="space-y-1 text-zsl-muted"> <div className="space-y-1 text-zsl-muted">
<div><span className="text-zsl-primary">$</span> find /page --name "{typeof window !== 'undefined' ? window.location.pathname : '/unknown'}"</div> <div><span className="text-zsl-primary">$</span> find /page --name &quot;/unknown&quot;</div>
<div className="text-red-400">Error: Page not found</div> <div className="text-red-400">Error: Page not found</div>
<div><span className="text-zsl-primary">$</span> suggest --redirect home</div> <div><span className="text-zsl-primary">$</span> suggest --redirect home</div>
<div className="text-zsl-accent">Suggestion: Return to homepage</div> <div className="text-zsl-accent">Suggestion: Return to homepage</div>
@@ -93,7 +107,6 @@ export default function NotFound() {
<div className="text-xs font-mono text-zsl-muted/30"> <div className="text-xs font-mono text-zsl-muted/30">
<div>STATUS: 404</div> <div>STATUS: 404</div>
<div>LOCATION: UNKNOWN</div> <div>LOCATION: UNKNOWN</div>
<div>TIME: {new Date().toISOString()}</div>
</div> </div>
</div> </div>

View File

@@ -17,6 +17,15 @@ import { CookieBanner } from '@/components/CookieBanner';
import { ProjectModal } from '@/components/ProjectModal'; import { ProjectModal } from '@/components/ProjectModal';
import { NavPage } from '@/types'; import { NavPage } from '@/types';
// Social Links
const socialLinks = {
github: "https://github.com/zerosixlab",
discord: "https://discord.gg/zerosixlab",
twitter: "https://twitter.com/zerosixlab",
linkedin: "https://linkedin.com/company/zerosixlab",
instagram: "https://instagram.com/zerosixlab"
};
// Data // Data
const testimonials = [ const testimonials = [
{ {
@@ -720,7 +729,7 @@ export default function Home() {
<AnimatedCounter <AnimatedCounter
end={30} end={30}
suffix="+" suffix="+"
title="Mutlu Müşteri" title="İş Ortağı"
icon={<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" /></svg>} icon={<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" /></svg>}
/> />
<AnimatedCounter <AnimatedCounter
@@ -732,7 +741,7 @@ export default function Home() {
<AnimatedCounter <AnimatedCounter
end={99} end={99}
suffix="%" suffix="%"
title="Müşteri Memnuniyeti" title="Proje Başarı Oranı"
icon={<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" /></svg>} icon={<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" /></svg>}
/> />
</div> </div>
@@ -783,8 +792,8 @@ export default function Home() {
<ScrollAnimation animation="fade-up" delay={200}> <ScrollAnimation animation="fade-up" delay={200}>
<div className="max-w-7xl mx-auto px-4 mt-32"> <div className="max-w-7xl mx-auto px-4 mt-32">
<div className="text-center mb-12"> <div className="text-center mb-12">
<span className="inline-block px-3 py-1 bg-white/5 rounded border border-white/10 text-xs font-mono tracking-widest text-zsl-accent mb-4">MÜŞTERİ YORUMLARI</span> <span className="inline-block px-3 py-1 bg-white/5 rounded border border-white/10 text-xs font-mono tracking-widest text-zsl-accent mb-4">REFERANSLAR</span>
<h2 className="text-3xl md:text-4xl font-mono font-bold text-white">Müşterilerimiz Ne Diyor?</h2> <h2 className="text-3xl md:text-4xl font-mono font-bold text-white">İş Ortaklarımız Ne Diyor?</h2>
</div> </div>
<TestimonialSlider testimonials={testimonials} /> <TestimonialSlider testimonials={testimonials} />
</div> </div>
@@ -910,28 +919,84 @@ export default function Home() {
</main> </main>
{/* Footer */} {/* Footer */}
<footer className="border-t border-white/5 bg-[#050B14] py-12 mt-20 relative overflow-hidden z-10"> <footer className="border-t border-white/5 bg-[#050B14] py-16 mt-20 relative overflow-hidden z-10">
<div className="absolute inset-0 cyber-grid opacity-10"></div> <div className="absolute inset-0 cyber-grid opacity-10"></div>
<div className="max-w-7xl mx-auto px-4 flex flex-col md:flex-row justify-between items-center gap-6 relative z-10"> <div className="max-w-7xl mx-auto px-4 relative z-10">
<div className="flex flex-col items-center md:items-start gap-2"> {/* Main Footer Content */}
<Logo size="sm" /> <div className="grid grid-cols-1 md:grid-cols-4 gap-12 mb-12">
<p className="font-mono text-slate-500 text-xs mt-2 text-center md:text-left"> {/* Brand */}
© 2024 ZeroSixLab. Tüm Hakları Saklıdır. <div className="md:col-span-1">
</p> <Logo size="sm" />
</div> <p className="font-mono text-slate-500 text-sm mt-4 leading-relaxed">
Ankara merkezli, global vizyonlu yeni nesil yazılım ve Ar-Ge laboratuvarı.
<div className="flex gap-6"> </p>
{['Twitter', 'LinkedIn', 'GitHub'].map((social) => ( </div>
<a key={social} href="#" className="text-slate-500 hover:text-zsl-primary transition-colors font-mono text-sm uppercase tracking-wider hover:underline decoration-zsl-primary underline-offset-4">{social}</a>
))} {/* Quick Links */}
<div>
<h4 className="font-mono text-white font-bold mb-4 text-sm uppercase tracking-wider">Keşfet</h4>
<ul className="space-y-2">
{[
{ label: 'Ana Sayfa', page: NavPage.HOME },
{ label: 'Çözümler', page: NavPage.SERVICES },
{ label: 'Projeler', page: NavPage.PROJECTS },
{ label: 'Hakkımızda', page: NavPage.ABOUT },
].map((item) => (
<li key={item.label}>
<button onClick={() => handleNavClick(item.page)} className="text-slate-500 hover:text-zsl-primary transition-colors text-sm">{item.label}</button>
</li>
))}
</ul>
</div>
{/* Services */}
<div>
<h4 className="font-mono text-white font-bold mb-4 text-sm uppercase tracking-wider">Hizmetler</h4>
<ul className="space-y-2 text-sm text-slate-500">
<li>Web Geliştirme</li>
<li>Mobil Uygulama</li>
<li>Yapay Zeka Çözümleri</li>
<li>Blockchain & Web3</li>
</ul>
</div>
{/* Contact & Social */}
<div>
<h4 className="font-mono text-white font-bold mb-4 text-sm uppercase tracking-wider">Bize Ulaşın</h4>
<p className="text-slate-500 text-sm mb-4">info@zerosixlab.com</p>
<div className="flex gap-3">
<a href={socialLinks.github} target="_blank" rel="noopener noreferrer" className="w-10 h-10 rounded-lg bg-white/5 border border-white/10 flex items-center justify-center text-slate-500 hover:text-zsl-primary hover:border-zsl-primary/50 transition-all">
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path fillRule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clipRule="evenodd" /></svg>
</a>
<a href={socialLinks.discord} target="_blank" rel="noopener noreferrer" className="w-10 h-10 rounded-lg bg-white/5 border border-white/10 flex items-center justify-center text-slate-500 hover:text-zsl-primary hover:border-zsl-primary/50 transition-all">
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"/></svg>
</a>
<a href={socialLinks.twitter} target="_blank" rel="noopener noreferrer" className="w-10 h-10 rounded-lg bg-white/5 border border-white/10 flex items-center justify-center text-slate-500 hover:text-zsl-primary hover:border-zsl-primary/50 transition-all">
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
</a>
<a href={socialLinks.linkedin} target="_blank" rel="noopener noreferrer" className="w-10 h-10 rounded-lg bg-white/5 border border-white/10 flex items-center justify-center text-slate-500 hover:text-zsl-primary hover:border-zsl-primary/50 transition-all">
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>
</a>
<a href={socialLinks.instagram} target="_blank" rel="noopener noreferrer" className="w-10 h-10 rounded-lg bg-white/5 border border-white/10 flex items-center justify-center text-slate-500 hover:text-zsl-primary hover:border-zsl-primary/50 transition-all">
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 100 12.324 6.162 6.162 0 000-12.324zM12 16a4 4 0 110-8 4 4 0 010 8zm6.406-11.845a1.44 1.44 0 100 2.881 1.44 1.44 0 000-2.881z"/></svg>
</a>
</div>
</div>
</div> </div>
<div className="flex items-center gap-4 border border-white/10 px-4 py-2 rounded bg-black/40"> {/* Bottom Bar */}
<div className="text-right hidden md:block"> <div className="pt-8 border-t border-white/5 flex flex-col md:flex-row justify-between items-center gap-4">
<div className="text-[10px] text-slate-500 font-mono uppercase tracking-widest">SYSTEM STATUS</div> <p className="font-mono text-slate-500 text-xs text-center md:text-left">
<div className="text-xs text-green-400 font-mono tracking-wider font-bold">ALL SYSTEMS OPERATIONAL</div> © 2024 ZeroSixLab. Tüm Hakları Saklıdır.
</div> </p>
<div className="w-2 h-2 rounded-full bg-green-500 shadow-[0_0_10px_#00ff00] animate-pulse"></div>
<div className="flex items-center gap-4 border border-white/10 px-4 py-2 rounded bg-black/40">
<div className="text-right hidden md:block">
<div className="text-[10px] text-slate-500 font-mono uppercase tracking-widest">SYSTEM STATUS</div>
<div className="text-xs text-green-400 font-mono tracking-wider font-bold">ALL SYSTEMS OPERATIONAL</div>
</div>
<div className="w-2 h-2 rounded-full bg-green-500 shadow-[0_0_10px_#00ff00] animate-pulse"></div>
</div>
</div> </div>
</div> </div>
</footer> </footer>

View File

@@ -0,0 +1,303 @@
'use client';
import { useState, useEffect } from 'react';
import Link from 'next/link';
import { Project } from '@/data/projects';
import { Logo } from '@/components/Logo';
import { CustomCursor } from '@/components/CustomCursor';
import { ParticleBackground } from '@/components/ParticleBackground';
import { ScrollToTop } from '@/components/ScrollToTop';
interface Props {
project: Project;
allProjects: Project[];
}
export default function ProjectDetailClient({ project, allProjects }: Props) {
const [isLoaded, setIsLoaded] = useState(false);
useEffect(() => {
setIsLoaded(true);
}, []);
const otherProjects = allProjects.filter(p => p.id !== project.id).slice(0, 3);
const statusColors = {
'Tamamlandı': 'bg-green-500/20 text-green-400 border-green-500/30',
'Devam Ediyor': 'bg-yellow-500/20 text-yellow-400 border-yellow-500/30',
'Bakımda': 'bg-blue-500/20 text-blue-400 border-blue-500/30'
};
return (
<div className="min-h-screen bg-[#0a0f1a] text-white">
<CustomCursor />
<ParticleBackground />
<ScrollToTop />
{/* Header */}
<header className="fixed top-0 left-0 right-0 z-50 bg-[#0a0f1a]/80 backdrop-blur-xl border-b border-white/5">
<div className="max-w-7xl mx-auto px-4 py-4 flex items-center justify-between">
<Link href="/" className="hover:opacity-80 transition-opacity">
<Logo size="sm" />
</Link>
<Link
href="/#projects"
className="flex items-center gap-2 text-slate-400 hover:text-white transition-colors font-mono text-sm"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg>
Tüm Projeler
</Link>
</div>
</header>
{/* Main Content */}
<main className={`pt-24 pb-20 transition-all duration-700 ${isLoaded ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'}`}>
<div className="max-w-6xl mx-auto px-4">
{/* Hero Section */}
<div className="mb-16">
<div className="flex flex-wrap items-center gap-3 mb-6">
<span className="px-3 py-1 bg-zsl-primary/20 text-zsl-primary border border-zsl-primary/30 rounded text-xs font-mono uppercase tracking-wider">
{project.category}
</span>
<span className={`px-3 py-1 border rounded text-xs font-mono ${statusColors[project.status]}`}>
{project.status}
</span>
<span className="text-slate-500 text-sm font-mono">{project.year}</span>
</div>
<h1 className="text-4xl md:text-6xl font-mono font-bold text-white mb-6 tracking-tight">
{project.title}
</h1>
<p className="text-xl text-slate-400 font-mono leading-relaxed max-w-3xl">
{project.description}
</p>
</div>
{/* Project Image */}
<div className="relative aspect-video rounded-2xl overflow-hidden mb-16 bg-linear-to-br from-zsl-primary/20 to-purple-500/20 border border-white/10">
<div className="absolute inset-0 flex items-center justify-center">
<div className="text-center">
<div className="w-24 h-24 mx-auto mb-4 rounded-2xl bg-linear-to-br from-zsl-primary to-purple-500 flex items-center justify-center text-4xl">
{project.category === 'Yapay Zeka' && '🤖'}
{project.category === 'Blockchain' && '⛓️'}
{project.category === 'Cloud' && '☁️'}
{project.category === 'Güvenlik' && '🛡️'}
{project.category === 'Big Data' && '📊'}
{project.category === 'IoT' && '📡'}
</div>
<span className="font-mono text-white/60 text-sm">Proje Görseli</span>
</div>
</div>
<div className="absolute inset-0 cyber-grid opacity-20"></div>
</div>
{/* Content Grid */}
<div className="grid md:grid-cols-3 gap-12">
{/* Main Content */}
<div className="md:col-span-2 space-y-12">
{/* Description */}
<section>
<h2 className="text-2xl font-mono font-bold text-white mb-6 flex items-center gap-3">
<span className="w-8 h-8 rounded bg-zsl-primary/20 flex items-center justify-center text-zsl-primary text-sm">01</span>
Proje Hakkında
</h2>
<div className="prose prose-invert max-w-none">
{project.longDescription.split('\n\n').map((paragraph, index) => (
<p key={index} className="text-slate-400 font-mono leading-relaxed mb-4">
{paragraph}
</p>
))}
</div>
</section>
{/* Features */}
<section>
<h2 className="text-2xl font-mono font-bold text-white mb-6 flex items-center gap-3">
<span className="w-8 h-8 rounded bg-zsl-primary/20 flex items-center justify-center text-zsl-primary text-sm">02</span>
Özellikler
</h2>
<div className="grid sm:grid-cols-2 gap-4">
{project.features.map((feature, index) => (
<div
key={index}
className="flex items-start gap-3 p-4 bg-white/5 border border-white/10 rounded-lg hover:border-zsl-primary/30 transition-colors"
>
<svg className="w-5 h-5 text-zsl-primary shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
<span className="text-slate-300 font-mono text-sm">{feature}</span>
</div>
))}
</div>
</section>
{/* Technologies */}
<section>
<h2 className="text-2xl font-mono font-bold text-white mb-6 flex items-center gap-3">
<span className="w-8 h-8 rounded bg-zsl-primary/20 flex items-center justify-center text-zsl-primary text-sm">03</span>
Teknolojiler
</h2>
<div className="flex flex-wrap gap-3">
{project.technologies.map((tech, index) => (
<span
key={index}
className="px-4 py-2 bg-white/5 border border-white/10 rounded-lg text-sm font-mono text-slate-300 hover:border-zsl-primary/50 hover:text-zsl-primary transition-colors cursor-default"
>
{tech}
</span>
))}
</div>
</section>
</div>
{/* Sidebar */}
<div className="space-y-6">
{/* Project Info Card */}
<div className="bg-white/5 border border-white/10 rounded-xl p-6 sticky top-24">
<h3 className="font-mono font-bold text-white mb-6">Proje Detayları</h3>
<div className="space-y-4">
<div className="flex justify-between items-center py-3 border-b border-white/5">
<span className="text-slate-500 font-mono text-sm">Durum</span>
<span className={`px-2 py-1 border rounded text-xs font-mono ${statusColors[project.status]}`}>
{project.status}
</span>
</div>
<div className="flex justify-between items-center py-3 border-b border-white/5">
<span className="text-slate-500 font-mono text-sm">Yıl</span>
<span className="text-white font-mono text-sm">{project.year}</span>
</div>
{project.duration && (
<div className="flex justify-between items-center py-3 border-b border-white/5">
<span className="text-slate-500 font-mono text-sm">Süre</span>
<span className="text-white font-mono text-sm">{project.duration}</span>
</div>
)}
{project.client && (
<div className="flex justify-between items-center py-3 border-b border-white/5">
<span className="text-slate-500 font-mono text-sm">İş Ortağı</span>
<span className="text-white font-mono text-sm">{project.client}</span>
</div>
)}
<div className="flex justify-between items-center py-3">
<span className="text-slate-500 font-mono text-sm">Kategori</span>
<span className="text-zsl-primary font-mono text-sm">{project.category}</span>
</div>
</div>
{/* Action Buttons */}
<div className="mt-6 space-y-3">
{project.link && (
<a
href={project.link}
target="_blank"
rel="noopener noreferrer"
className="flex items-center justify-center gap-2 w-full py-3 bg-linear-to-r from-zsl-primary to-cyan-400 text-black font-mono font-bold rounded-lg hover:shadow-[0_0_20px_rgba(0,212,255,0.4)] transition-all"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
</svg>
Demo İncele
</a>
)}
{project.github && (
<a
href={project.github}
target="_blank"
rel="noopener noreferrer"
className="flex items-center justify-center gap-2 w-full py-3 border border-white/20 text-white font-mono rounded-lg hover:border-zsl-primary/50 hover:text-zsl-primary transition-all"
>
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
<path fillRule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clipRule="evenodd" />
</svg>
GitHub
</a>
)}
<Link
href="/#contact"
className="flex items-center justify-center gap-2 w-full py-3 border border-white/20 text-white font-mono rounded-lg hover:border-zsl-accent/50 hover:text-zsl-accent transition-all"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
</svg>
Benzer Proje İste
</Link>
</div>
{/* Tags */}
<div className="mt-6 pt-6 border-t border-white/10">
<div className="flex flex-wrap gap-2">
{project.tags.map((tag, index) => (
<span key={index} className="px-2 py-1 bg-white/5 text-slate-500 text-xs font-mono rounded">
#{tag}
</span>
))}
</div>
</div>
</div>
</div>
</div>
{/* Other Projects */}
<section className="mt-24">
<h2 className="text-2xl font-mono font-bold text-white mb-8">Diğer Projeler</h2>
<div className="grid md:grid-cols-3 gap-6">
{otherProjects.map((p) => (
<Link
key={p.id}
href={`/projects/${p.slug}`}
className="group bg-white/5 border border-white/10 rounded-xl overflow-hidden hover:border-zsl-primary/50 transition-all duration-300"
>
<div className="aspect-video bg-linear-to-br from-zsl-primary/10 to-purple-500/10 flex items-center justify-center">
<span className="text-4xl">
{p.category === 'Yapay Zeka' && '🤖'}
{p.category === 'Blockchain' && '⛓️'}
{p.category === 'Cloud' && '☁️'}
{p.category === 'Güvenlik' && '🛡️'}
{p.category === 'Big Data' && '📊'}
{p.category === 'IoT' && '📡'}
</span>
</div>
<div className="p-4">
<span className="text-xs font-mono text-zsl-primary">{p.category}</span>
<h3 className="font-mono font-bold text-white mt-1 group-hover:text-zsl-primary transition-colors">
{p.title}
</h3>
<p className="text-sm text-slate-500 font-mono mt-2 line-clamp-2">
{p.description}
</p>
</div>
</Link>
))}
</div>
</section>
</div>
</main>
{/* Footer */}
<footer className="border-t border-white/5 bg-[#050B14] py-8">
<div className="max-w-6xl mx-auto px-4 flex flex-col md:flex-row justify-between items-center gap-4">
<Link href="/" className="hover:opacity-80 transition-opacity">
<Logo size="sm" />
</Link>
<p className="font-mono text-slate-500 text-xs">
© 2024 ZeroSixLab. Tüm Hakları Saklıdır.
</p>
</div>
</footer>
</div>
);
}

View File

@@ -0,0 +1,46 @@
import { Metadata } from 'next';
import { notFound } from 'next/navigation';
import { getProjectBySlug, getAllProjectSlugs, projects } from '@/data/projects';
import ProjectDetailClient from './ProjectDetailClient';
interface Props {
params: Promise<{ slug: string }>;
}
export async function generateStaticParams() {
return getAllProjectSlugs().map((slug) => ({
slug,
}));
}
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { slug } = await params;
const project = getProjectBySlug(slug);
if (!project) {
return {
title: 'Proje Bulunamadı | ZeroSixLab',
};
}
return {
title: `${project.title} | ZeroSixLab`,
description: project.description,
openGraph: {
title: `${project.title} | ZeroSixLab`,
description: project.description,
images: [project.image],
},
};
}
export default async function ProjectPage({ params }: Props) {
const { slug } = await params;
const project = getProjectBySlug(slug);
if (!project) {
notFound();
}
return <ProjectDetailClient project={project} allProjects={projects} />;
}

58
src/app/sitemap.ts Normal file
View File

@@ -0,0 +1,58 @@
import { MetadataRoute } from 'next'
export default function sitemap(): MetadataRoute.Sitemap {
const baseUrl = 'https://zerosixlab.com'
// Static pages
const staticPages = [
{
url: baseUrl,
lastModified: new Date(),
changeFrequency: 'weekly' as const,
priority: 1,
},
{
url: `${baseUrl}/#services`,
lastModified: new Date(),
changeFrequency: 'monthly' as const,
priority: 0.8,
},
{
url: `${baseUrl}/#projects`,
lastModified: new Date(),
changeFrequency: 'weekly' as const,
priority: 0.9,
},
{
url: `${baseUrl}/#about`,
lastModified: new Date(),
changeFrequency: 'monthly' as const,
priority: 0.7,
},
{
url: `${baseUrl}/#contact`,
lastModified: new Date(),
changeFrequency: 'monthly' as const,
priority: 0.8,
},
]
// Project pages
const projects = [
'aurora-ai',
'quantumledger',
'nexuscloud',
'cyberguard',
'dataforge',
'smartcity'
]
const projectPages = projects.map((slug) => ({
url: `${baseUrl}/projects/${slug}`,
lastModified: new Date(),
changeFrequency: 'monthly' as const,
priority: 0.6,
}))
return [...staticPages, ...projectPages]
}

View File

@@ -0,0 +1,225 @@
'use client';
import { useState, useRef, FormEvent } from 'react';
// EmailJS configuration - Replace with your actual IDs
const EMAILJS_SERVICE_ID = 'YOUR_SERVICE_ID';
const EMAILJS_TEMPLATE_ID = 'YOUR_TEMPLATE_ID';
const EMAILJS_PUBLIC_KEY = 'YOUR_PUBLIC_KEY';
interface ContactFormData {
name: string;
email: string;
subject: string;
message: string;
}
interface FormStatus {
type: 'idle' | 'loading' | 'success' | 'error';
message: string;
}
export default function ContactForm() {
const formRef = useRef<HTMLFormElement>(null);
const [formData, setFormData] = useState<ContactFormData>({
name: '',
email: '',
subject: '',
message: ''
});
const [status, setStatus] = useState<FormStatus>({ type: 'idle', message: '' });
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
};
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
// Validation
if (!formData.name || !formData.email || !formData.message) {
setStatus({ type: 'error', message: 'Lütfen tüm zorunlu alanları doldurun.' });
return;
}
// Email validation
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(formData.email)) {
setStatus({ type: 'error', message: 'Geçerli bir e-posta adresi girin.' });
return;
}
setStatus({ type: 'loading', message: 'Gönderiliyor...' });
try {
// Dynamic import for EmailJS to reduce bundle size
const emailjs = await import('@emailjs/browser');
await emailjs.sendForm(
EMAILJS_SERVICE_ID,
EMAILJS_TEMPLATE_ID,
formRef.current!,
EMAILJS_PUBLIC_KEY
);
setStatus({ type: 'success', message: 'Mesajınız başarıyla gönderildi! En kısa sürede dönüş yapacağız.' });
setFormData({ name: '', email: '', subject: '', message: '' });
} catch (error) {
console.error('EmailJS Error:', error);
setStatus({
type: 'error',
message: 'Mesaj gönderilemedi. Lütfen daha sonra tekrar deneyin veya doğrudan e-posta gönderin.'
});
}
};
const subjects = [
'Web Geliştirme',
'Mobil Uygulama',
'Yapay Zeka Çözümleri',
'Blockchain & Web3',
'Danışmanlık',
'Diğer'
];
return (
<form ref={formRef} onSubmit={handleSubmit} className="space-y-6">
{/* Name Field */}
<div>
<label htmlFor="name" className="block text-sm font-mono text-slate-400 mb-2">
İsim <span className="text-red-400">*</span>
</label>
<input
type="text"
id="name"
name="name"
value={formData.name}
onChange={handleChange}
placeholder="Adınız Soyadınız"
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-lg text-white placeholder:text-slate-600 focus:outline-none focus:border-zsl-primary/50 focus:ring-1 focus:ring-zsl-primary/50 transition-all font-mono text-sm"
disabled={status.type === 'loading'}
/>
</div>
{/* Email Field */}
<div>
<label htmlFor="email" className="block text-sm font-mono text-slate-400 mb-2">
E-posta <span className="text-red-400">*</span>
</label>
<input
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleChange}
placeholder="ornek@email.com"
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-lg text-white placeholder:text-slate-600 focus:outline-none focus:border-zsl-primary/50 focus:ring-1 focus:ring-zsl-primary/50 transition-all font-mono text-sm"
disabled={status.type === 'loading'}
/>
</div>
{/* Subject Field */}
<div>
<label htmlFor="subject" className="block text-sm font-mono text-slate-400 mb-2">
Konu
</label>
<select
id="subject"
name="subject"
value={formData.subject}
onChange={handleChange}
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-lg text-white focus:outline-none focus:border-zsl-primary/50 focus:ring-1 focus:ring-zsl-primary/50 transition-all font-mono text-sm appearance-none cursor-pointer"
disabled={status.type === 'loading'}
>
<option value="" className="bg-[#0a0f1a]">Konu Seçin</option>
{subjects.map((subj) => (
<option key={subj} value={subj} className="bg-[#0a0f1a]">
{subj}
</option>
))}
</select>
</div>
{/* Message Field */}
<div>
<label htmlFor="message" className="block text-sm font-mono text-slate-400 mb-2">
Mesaj <span className="text-red-400">*</span>
</label>
<textarea
id="message"
name="message"
value={formData.message}
onChange={handleChange}
placeholder="Projeniz hakkında detayları paylaşın..."
rows={5}
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-lg text-white placeholder:text-slate-600 focus:outline-none focus:border-zsl-primary/50 focus:ring-1 focus:ring-zsl-primary/50 transition-all font-mono text-sm resize-none"
disabled={status.type === 'loading'}
/>
</div>
{/* Status Message */}
{status.type !== 'idle' && (
<div className={`p-4 rounded-lg border font-mono text-sm ${
status.type === 'success'
? 'bg-green-500/10 border-green-500/30 text-green-400'
: status.type === 'error'
? 'bg-red-500/10 border-red-500/30 text-red-400'
: 'bg-zsl-primary/10 border-zsl-primary/30 text-zsl-primary'
}`}>
<div className="flex items-center gap-2">
{status.type === 'loading' && (
<svg className="w-4 h-4 animate-spin" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
)}
{status.type === 'success' && (
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
)}
{status.type === 'error' && (
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
)}
{status.message}
</div>
</div>
)}
{/* Submit Button */}
<button
type="submit"
disabled={status.type === 'loading'}
className="w-full group relative overflow-hidden bg-linear-to-r from-zsl-primary to-cyan-400 text-black font-mono font-bold py-4 px-6 rounded-lg transition-all duration-300 hover:shadow-[0_0_30px_rgba(0,212,255,0.4)] disabled:opacity-50 disabled:cursor-not-allowed"
>
<span className="relative z-10 flex items-center justify-center gap-2">
{status.type === 'loading' ? (
<>
<svg className="w-5 h-5 animate-spin" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
GÖNDERİLİYOR...
</>
) : (
<>
MESAJ GÖNDER
<svg className="w-5 h-5 group-hover:translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14 5l7 7m0 0l-7 7m7-7H3" />
</svg>
</>
)}
</span>
<div className="absolute inset-0 bg-linear-to-r from-cyan-400 to-zsl-primary opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
</button>
{/* Privacy Note */}
<p className="text-xs text-slate-600 font-mono text-center">
Formu göndererek <span className="text-slate-500">Gizlilik Politikamızı</span> kabul etmiş olursunuz.
</p>
</form>
);
}

View File

@@ -1,9 +1,10 @@
"use client"; "use client";
import React, { useEffect, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
export const CustomCursor: React.FC = () => { export const CustomCursor: React.FC = () => {
const [position, setPosition] = useState({ x: 0, y: 0 }); const cursorRef = useRef<HTMLDivElement>(null);
const ringRef = useRef<HTMLDivElement>(null);
const [isPointer, setIsPointer] = useState(false); const [isPointer, setIsPointer] = useState(false);
const [isClicking, setIsClicking] = useState(false); const [isClicking, setIsClicking] = useState(false);
const [isVisible, setIsVisible] = useState(false); const [isVisible, setIsVisible] = useState(false);
@@ -13,10 +14,22 @@ export const CustomCursor: React.FC = () => {
const hasHover = window.matchMedia('(hover: hover)').matches; const hasHover = window.matchMedia('(hover: hover)').matches;
if (!hasHover) return; if (!hasHover) return;
let mouseX = 0;
let mouseY = 0;
let ringX = 0;
let ringY = 0;
const handleMouseMove = (e: MouseEvent) => { const handleMouseMove = (e: MouseEvent) => {
setPosition({ x: e.clientX, y: e.clientY }); mouseX = e.clientX;
mouseY = e.clientY;
setIsVisible(true); setIsVisible(true);
// Instantly move main cursor
if (cursorRef.current) {
cursorRef.current.style.left = `${mouseX}px`;
cursorRef.current.style.top = `${mouseY}px`;
}
const target = e.target as HTMLElement; const target = e.target as HTMLElement;
const isClickable = !!( const isClickable = !!(
target.tagName === 'BUTTON' || target.tagName === 'BUTTON' ||
@@ -30,6 +43,19 @@ export const CustomCursor: React.FC = () => {
setIsPointer(isClickable); setIsPointer(isClickable);
}; };
// Smooth follow for outer ring
const animateRing = () => {
ringX += (mouseX - ringX) * 0.15;
ringY += (mouseY - ringY) * 0.15;
if (ringRef.current) {
ringRef.current.style.left = `${ringX}px`;
ringRef.current.style.top = `${ringY}px`;
}
requestAnimationFrame(animateRing);
};
const handleMouseDown = () => setIsClicking(true); const handleMouseDown = () => setIsClicking(true);
const handleMouseUp = () => setIsClicking(false); const handleMouseUp = () => setIsClicking(false);
const handleMouseLeave = () => setIsVisible(false); const handleMouseLeave = () => setIsVisible(false);
@@ -41,6 +67,9 @@ export const CustomCursor: React.FC = () => {
document.documentElement.addEventListener('mouseleave', handleMouseLeave); document.documentElement.addEventListener('mouseleave', handleMouseLeave);
document.documentElement.addEventListener('mouseenter', handleMouseEnter); document.documentElement.addEventListener('mouseenter', handleMouseEnter);
// Start animation loop
const animationId = requestAnimationFrame(animateRing);
// Hide default cursor // Hide default cursor
document.body.style.cursor = 'none'; document.body.style.cursor = 'none';
document.querySelectorAll('a, button').forEach(el => { document.querySelectorAll('a, button').forEach(el => {
@@ -54,6 +83,7 @@ export const CustomCursor: React.FC = () => {
document.documentElement.removeEventListener('mouseleave', handleMouseLeave); document.documentElement.removeEventListener('mouseleave', handleMouseLeave);
document.documentElement.removeEventListener('mouseenter', handleMouseEnter); document.documentElement.removeEventListener('mouseenter', handleMouseEnter);
document.body.style.cursor = 'auto'; document.body.style.cursor = 'auto';
cancelAnimationFrame(animationId);
}; };
}, []); }, []);
@@ -61,51 +91,37 @@ export const CustomCursor: React.FC = () => {
return ( return (
<> <>
{/* Main cursor dot */} {/* Main cursor dot - instantly follows mouse */}
<div <div
className="fixed pointer-events-none z-9999 mix-blend-difference" ref={cursorRef}
className="fixed pointer-events-none z-9999"
style={{ style={{
left: position.x,
top: position.y,
transform: 'translate(-50%, -50%)', transform: 'translate(-50%, -50%)',
}} }}
> >
<div <div
className={` className={`
rounded-full bg-zsl-primary transition-all duration-150 ease-out rounded-full bg-zsl-primary transition-all duration-75 ease-out
${isClicking ? 'w-2 h-2' : isPointer ? 'w-4 h-4' : 'w-3 h-3'} ${isClicking ? 'w-2 h-2' : isPointer ? 'w-4 h-4' : 'w-3 h-3'}
`} `}
/> />
</div> </div>
{/* Outer ring */} {/* Outer ring - smooth follow */}
<div <div
className="fixed pointer-events-none z-9998 transition-all duration-300 ease-out" ref={ringRef}
className="fixed pointer-events-none z-9998"
style={{ style={{
left: position.x,
top: position.y,
transform: 'translate(-50%, -50%)', transform: 'translate(-50%, -50%)',
}} }}
> >
<div <div
className={` className={`
rounded-full border-2 border-zsl-primary/50 transition-all duration-200 ease-out rounded-full border-2 border-zsl-primary/50 transition-all duration-100 ease-out
${isClicking ? 'w-6 h-6 border-zsl-accent' : isPointer ? 'w-10 h-10 border-zsl-accent' : 'w-8 h-8'} ${isClicking ? 'w-6 h-6 border-zsl-accent' : isPointer ? 'w-10 h-10 border-zsl-accent' : 'w-8 h-8'}
`} `}
/> />
</div> </div>
{/* Glow trail effect */}
<div
className="fixed pointer-events-none z-9997 transition-all duration-500 ease-out opacity-30"
style={{
left: position.x,
top: position.y,
transform: 'translate(-50%, -50%)',
}}
>
<div className="w-16 h-16 rounded-full bg-zsl-primary/20 blur-xl" />
</div>
</> </>
); );
}; };

190
src/data/projects.ts Normal file
View File

@@ -0,0 +1,190 @@
// Project data shared between pages
export interface Project {
id: string;
slug: string;
title: string;
category: string;
description: string;
longDescription: string;
image: string;
tags: string[];
technologies: string[];
features: string[];
status: 'Tamamlandı' | 'Devam Ediyor' | 'Bakımda';
year: string;
client?: string;
duration?: string;
link?: string;
github?: string;
}
export const projects: Project[] = [
{
id: '1',
slug: 'aurora-ai',
title: 'Aurora AI',
category: 'Yapay Zeka',
description: 'Doğal dil işleme ve makine öğrenimi ile güçlendirilmiş kurumsal yapay zeka asistanı.',
longDescription: `Aurora AI, işletmelerin müşteri hizmetlerini ve iç süreçlerini otomatize etmek için geliştirdiğimiz yapay zeka çözümüdür.
Doğal dil işleme (NLP) teknolojileri kullanarak Türkçe dahil 15+ dilde akıcı konuşma yapabilen bu sistem, GPT tabanlı modellerle entegre çalışır.
Müşteri hizmetleri, HR süreçleri, teknik destek ve satış asistanlığı gibi birçok alanda kullanılabilir. Öğrenme yeteneği sayesinde her geçen gün daha akıllı hale gelir.`,
image: '/projects/aurora-ai.jpg',
tags: ['AI', 'NLP', 'Machine Learning', 'Enterprise'],
technologies: ['Python', 'TensorFlow', 'FastAPI', 'React', 'PostgreSQL', 'Redis', 'Docker', 'Kubernetes'],
features: [
'15+ dilde doğal dil desteği',
'GPT-4 ve Claude entegrasyonu',
'Özel model eğitimi',
'CRM ve ERP entegrasyonları',
'Gerçek zamanlı analytics',
'Multi-tenant mimari'
],
status: 'Tamamlandı',
year: '2024',
duration: '8 ay',
link: 'https://aurora-ai.demo.zerosixlab.com'
},
{
id: '2',
slug: 'quantumledger',
title: 'QuantumLedger',
category: 'Blockchain',
description: 'Kurumsal seviye dağıtık defter teknolojisi ve akıllı sözleşme platformu.',
longDescription: `QuantumLedger, finansal kurumlar için geliştirdiğimiz özel blockchain çözümüdür.
Hyperledger Fabric tabanlı bu platform, saniyede 10,000+ işlem kapasitesi ile yüksek performans sunar. Akıllı sözleşmeler ile otomatik uyumluluk kontrolü ve denetim izi sağlar.
Özellikle bankacılık, sigorta ve tedarik zinciri sektörlerinde kullanılmak üzere tasarlanmıştır.`,
image: '/projects/quantumledger.jpg',
tags: ['Blockchain', 'DeFi', 'Smart Contracts', 'Fintech'],
technologies: ['Solidity', 'Hyperledger Fabric', 'Go', 'Node.js', 'React', 'MongoDB', 'AWS'],
features: [
'10,000+ TPS performans',
'Akıllı sözleşme desteği',
'Çoklu konsensüs mekanizması',
'Regülasyon uyumluluğu',
'Gerçek zamanlı izleme',
'API gateway'
],
status: 'Tamamlandı',
year: '2024',
client: 'Gizli (NDA)',
duration: '12 ay'
},
{
id: '3',
slug: 'nexuscloud',
title: 'NexusCloud',
category: 'Cloud',
description: 'Hibrit bulut yönetimi ve orkestrasyon platformu.',
longDescription: `NexusCloud, çoklu bulut ortamlarını tek bir panelden yönetmenizi sağlayan orkestrasyon platformudur.
AWS, Azure, GCP ve on-premise sistemleri entegre ederek hibrit bulut stratejinizi kolaylaştırır. Kubernetes tabanlı konteyner orkestrasyonu, otomatik ölçeklendirme ve maliyet optimizasyonu özellikleri sunar.
DevOps ekipleri için CI/CD pipeline entegrasyonları ve Infrastructure as Code desteği ile tam otomasyon sağlar.`,
image: '/projects/nexuscloud.jpg',
tags: ['Cloud', 'DevOps', 'Kubernetes', 'IaC'],
technologies: ['Go', 'Kubernetes', 'Terraform', 'React', 'GraphQL', 'TimescaleDB', 'Prometheus'],
features: [
'Multi-cloud yönetimi',
'Otomatik ölçeklendirme',
'Maliyet optimizasyonu',
'CI/CD entegrasyonu',
'Infrastructure as Code',
'Gerçek zamanlı monitoring'
],
status: 'Devam Ediyor',
year: '2024',
duration: '6 ay (devam ediyor)'
},
{
id: '4',
slug: 'cyberguard',
title: 'CyberGuard',
category: 'Güvenlik',
description: 'AI destekli siber tehdit algılama ve yanıt sistemi.',
longDescription: `CyberGuard, yapay zeka destekli siber güvenlik çözümümüzdür.
Makine öğrenimi algoritmaları ile anormal davranışları tespit eder, zero-day saldırılarını önler ve otomatik yanıt mekanizmaları ile tehditleri nötralize eder.
SIEM sistemleri, firewall'lar ve endpoint protection çözümleri ile entegre çalışarak 360 derece güvenlik sağlar.`,
image: '/projects/cyberguard.jpg',
tags: ['Security', 'AI', 'Threat Detection', 'SIEM'],
technologies: ['Python', 'Rust', 'Elasticsearch', 'Kafka', 'React', 'TensorFlow', 'Docker'],
features: [
'AI tabanlı tehdit algılama',
'Zero-day koruma',
'Otomatik yanıt sistemi',
'SIEM entegrasyonu',
'Compliance raporlama',
'7/24 SOC desteği'
],
status: 'Tamamlandı',
year: '2023',
duration: '10 ay',
link: 'https://cyberguard.demo.zerosixlab.com'
},
{
id: '5',
slug: 'dataforge',
title: 'DataForge',
category: 'Big Data',
description: 'Büyük veri işleme ve gerçek zamanlı analitik platformu.',
longDescription: `DataForge, petabayt ölçeğinde veri işleme kapasitesine sahip analitik platformumuzdur.
Apache Spark ve Flink tabanlı stream processing ile gerçek zamanlı veri analizi yapar. Özelleştirilebilir dashboard'lar ve raporlama araçları ile veriden değer çıkarır.
E-ticaret, telekomünikasyon ve IoT sektörlerinde kullanılan bu platform, veri mühendisliği süreçlerini otomatize eder.`,
image: '/projects/dataforge.jpg',
tags: ['Big Data', 'Analytics', 'Real-time', 'ETL'],
technologies: ['Scala', 'Apache Spark', 'Apache Flink', 'Kafka', 'Airflow', 'Snowflake', 'dbt'],
features: [
'Petabayt ölçeği',
'Gerçek zamanlı stream processing',
'ETL/ELT pipeline\'lar',
'Özel dashboard\'lar',
'ML model entegrasyonu',
'Data governance'
],
status: 'Tamamlandı',
year: '2024',
duration: '9 ay'
},
{
id: '6',
slug: 'smartcity',
title: 'SmartCity IoT',
category: 'IoT',
description: 'Akıllı şehir altyapısı için IoT sensör yönetim sistemi.',
longDescription: `SmartCity IoT, belediyeler ve altyapı şirketleri için geliştirdiğimiz akıllı şehir çözümüdür.
Trafik yönetimi, enerji optimizasyonu, atık yönetimi ve çevre izleme gibi birçok alanda IoT sensörlerden toplanan verileri analiz eder.
Edge computing ile düşük latency, mesh network ile yüksek erişilebilirlik sağlar. Yapay zeka ile predictive maintenance yaparak arızaları önceden tespit eder.`,
image: '/projects/smartcity.jpg',
tags: ['IoT', 'Smart City', 'Edge Computing', 'AI'],
technologies: ['C++', 'Rust', 'MQTT', 'InfluxDB', 'Grafana', 'TensorFlow Lite', 'React Native'],
features: [
'100,000+ sensör desteği',
'Edge computing',
'Predictive maintenance',
'Enerji optimizasyonu',
'Trafik yönetimi',
'Çevre izleme'
],
status: 'Devam Ediyor',
year: '2024',
client: 'Büyükşehir Belediyesi',
duration: '18 ay (devam ediyor)'
}
];
export function getProjectBySlug(slug: string): Project | undefined {
return projects.find(p => p.slug === slug);
}
export function getAllProjectSlugs(): string[] {
return projects.map(p => p.slug);
}