master
41
my-app/.gitignore
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.*
|
||||||
|
.yarn/*
|
||||||
|
!.yarn/patches
|
||||||
|
!.yarn/plugins
|
||||||
|
!.yarn/releases
|
||||||
|
!.yarn/versions
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# next.js
|
||||||
|
/.next/
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
# debug
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
.pnpm-debug.log*
|
||||||
|
|
||||||
|
# env files (can opt-in for committing if needed)
|
||||||
|
.env*
|
||||||
|
|
||||||
|
# vercel
|
||||||
|
.vercel
|
||||||
|
|
||||||
|
# typescript
|
||||||
|
*.tsbuildinfo
|
||||||
|
next-env.d.ts
|
||||||
36
my-app/README.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
First, run the development server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
# or
|
||||||
|
yarn dev
|
||||||
|
# or
|
||||||
|
pnpm dev
|
||||||
|
# or
|
||||||
|
bun dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||||
|
|
||||||
|
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||||
|
|
||||||
|
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||||
|
|
||||||
|
## Learn More
|
||||||
|
|
||||||
|
To learn more about Next.js, take a look at the following resources:
|
||||||
|
|
||||||
|
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||||
|
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||||
|
|
||||||
|
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||||
|
|
||||||
|
## Deploy on Vercel
|
||||||
|
|
||||||
|
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||||
|
|
||||||
|
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||||
18
my-app/eslint.config.mjs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { defineConfig, globalIgnores } from "eslint/config";
|
||||||
|
import nextVitals from "eslint-config-next/core-web-vitals";
|
||||||
|
import nextTs from "eslint-config-next/typescript";
|
||||||
|
|
||||||
|
const eslintConfig = defineConfig([
|
||||||
|
...nextVitals,
|
||||||
|
...nextTs,
|
||||||
|
// Override default ignores of eslint-config-next.
|
||||||
|
globalIgnores([
|
||||||
|
// Default ignores of eslint-config-next:
|
||||||
|
".next/**",
|
||||||
|
"out/**",
|
||||||
|
"build/**",
|
||||||
|
"next-env.d.ts",
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
export default eslintConfig;
|
||||||
7
my-app/next.config.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import type { NextConfig } from "next";
|
||||||
|
|
||||||
|
const nextConfig: NextConfig = {
|
||||||
|
/* config options here */
|
||||||
|
};
|
||||||
|
|
||||||
|
export default nextConfig;
|
||||||
6538
my-app/package-lock.json
generated
Normal file
26
my-app/package.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name": "my-app",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start",
|
||||||
|
"lint": "eslint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"next": "16.0.10",
|
||||||
|
"react": "19.2.1",
|
||||||
|
"react-dom": "19.2.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tailwindcss/postcss": "^4",
|
||||||
|
"@types/node": "^20",
|
||||||
|
"@types/react": "^19",
|
||||||
|
"@types/react-dom": "^19",
|
||||||
|
"eslint": "^9",
|
||||||
|
"eslint-config-next": "16.0.10",
|
||||||
|
"tailwindcss": "^4",
|
||||||
|
"typescript": "^5"
|
||||||
|
}
|
||||||
|
}
|
||||||
7
my-app/postcss.config.mjs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
const config = {
|
||||||
|
plugins: {
|
||||||
|
"@tailwindcss/postcss": {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
BIN
my-app/public/assets/logo.png
Normal file
|
After Width: | Height: | Size: 2.5 MiB |
1
my-app/public/file.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 391 B |
1
my-app/public/globe.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
79
my-app/public/manifest.json
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
{
|
||||||
|
"name": "ZeroSixLab",
|
||||||
|
"short_name": "ZSL",
|
||||||
|
"description": "Ankara merkezli, global vizyonlu yeni nesil yazılım ve Ar-Ge laboratuvarı.",
|
||||||
|
"start_url": "/",
|
||||||
|
"display": "standalone",
|
||||||
|
"background_color": "#0A0E17",
|
||||||
|
"theme_color": "#00D4FF",
|
||||||
|
"orientation": "portrait-primary",
|
||||||
|
"scope": "/",
|
||||||
|
"lang": "tr",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/icons/icon-72x72.png",
|
||||||
|
"sizes": "72x72",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/icon-96x96.png",
|
||||||
|
"sizes": "96x96",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/icon-128x128.png",
|
||||||
|
"sizes": "128x128",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/icon-144x144.png",
|
||||||
|
"sizes": "144x144",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/icon-152x152.png",
|
||||||
|
"sizes": "152x152",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/icon-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/icon-384x384.png",
|
||||||
|
"sizes": "384x384",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/icon-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"categories": ["business", "productivity", "utilities"],
|
||||||
|
"screenshots": [
|
||||||
|
{
|
||||||
|
"src": "/screenshots/desktop.png",
|
||||||
|
"sizes": "1920x1080",
|
||||||
|
"type": "image/png",
|
||||||
|
"form_factor": "wide"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/screenshots/mobile.png",
|
||||||
|
"sizes": "390x844",
|
||||||
|
"type": "image/png",
|
||||||
|
"form_factor": "narrow"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"related_applications": [],
|
||||||
|
"prefer_related_applications": false
|
||||||
|
}
|
||||||
1
my-app/public/next.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
1
my-app/public/vercel.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
|
||||||
|
After Width: | Height: | Size: 128 B |
1
my-app/public/window.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
|
||||||
|
After Width: | Height: | Size: 385 B |
BIN
my-app/src/app/favicon.ico
Normal file
|
After Width: | Height: | Size: 25 KiB |
107
my-app/src/app/globals.css
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
@import "tailwindcss";
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--foreground-rgb: 226, 232, 240;
|
||||||
|
--background-start-rgb: 10, 25, 47;
|
||||||
|
--background-end-rgb: 10, 25, 47;
|
||||||
|
|
||||||
|
--background: #050B14;
|
||||||
|
--foreground: #E2E8F0;
|
||||||
|
|
||||||
|
--zsl-bg: #050B14;
|
||||||
|
--zsl-text: #E2E8F0;
|
||||||
|
--zsl-primary: #00D4FF;
|
||||||
|
--zsl-accent: #FFAA00;
|
||||||
|
--zsl-card: #0F172A;
|
||||||
|
--zsl-muted: #94A3B8;
|
||||||
|
}
|
||||||
|
|
||||||
|
@theme inline {
|
||||||
|
--color-background: var(--background);
|
||||||
|
--color-foreground: var(--foreground);
|
||||||
|
--font-sans: var(--font-geist-sans);
|
||||||
|
--font-mono: var(--font-geist-mono);
|
||||||
|
|
||||||
|
--color-zsl-bg: var(--zsl-bg);
|
||||||
|
--color-zsl-text: var(--zsl-text);
|
||||||
|
--color-zsl-primary: var(--zsl-primary);
|
||||||
|
--color-zsl-accent: var(--zsl-accent);
|
||||||
|
--color-zsl-card: var(--zsl-card);
|
||||||
|
--color-zsl-muted: var(--zsl-muted);
|
||||||
|
|
||||||
|
--animate-scroll: scroll 40s linear infinite;
|
||||||
|
--animate-pulse-slow: pulse 4s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||||
|
--animate-grid-move: grid-move 20s linear infinite;
|
||||||
|
|
||||||
|
@keyframes scroll {
|
||||||
|
0% { transform: translateX(0); }
|
||||||
|
100% { transform: translateX(-50%); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes grid-move {
|
||||||
|
0% { background-position: 0 0; }
|
||||||
|
100% { background-position: 50px 50px; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: rgb(var(--foreground-rgb));
|
||||||
|
background: linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
transparent,
|
||||||
|
rgb(var(--background-end-rgb))
|
||||||
|
)
|
||||||
|
rgb(var(--background-start-rgb));
|
||||||
|
overflow-x: hidden;
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom Scrollbar */
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: #0A192F;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: #1e293b;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #0A192F;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #00D4FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glass-panel {
|
||||||
|
background: rgba(17, 34, 64, 0.7);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border: 1px solid rgba(0, 212, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cyber-grid {
|
||||||
|
background-image:
|
||||||
|
linear-gradient(to right, rgba(0, 212, 255, 0.03) 1px, transparent 1px),
|
||||||
|
linear-gradient(to bottom, rgba(0, 212, 255, 0.03) 1px, transparent 1px);
|
||||||
|
background-size: 40px 40px;
|
||||||
|
mask-image: radial-gradient(circle at 50% 50%, black 30%, transparent 80%);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scanlines {
|
||||||
|
background: linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
rgba(255,255,255,0),
|
||||||
|
rgba(255,255,255,0) 50%,
|
||||||
|
rgba(0,0,0,0.2) 50%,
|
||||||
|
rgba(0,0,0,0.2)
|
||||||
|
);
|
||||||
|
background-size: 100% 4px;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 9999;
|
||||||
|
opacity: 0.15;
|
||||||
|
}
|
||||||
98
my-app/src/app/layout.tsx
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import type { Metadata, Viewport } from "next";
|
||||||
|
import { Inter, Orbitron } from "next/font/google";
|
||||||
|
import React from 'react';
|
||||||
|
import "./globals.css";
|
||||||
|
|
||||||
|
const inter = Inter({ subsets: ["latin"], variable: "--font-inter" });
|
||||||
|
const orbitron = Orbitron({ subsets: ["latin"], variable: "--font-orbitron" });
|
||||||
|
|
||||||
|
export const viewport: Viewport = {
|
||||||
|
width: 'device-width',
|
||||||
|
initialScale: 1,
|
||||||
|
themeColor: '#00D4FF',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: {
|
||||||
|
default: "ZeroSixLab - Geleceği Kodlayan Laboratuvar",
|
||||||
|
template: "%s | ZeroSixLab"
|
||||||
|
},
|
||||||
|
description: "Ankara merkezli, global vizyonlu yeni nesil yazılım ve Ar-Ge laboratuvarı. Web, mobil, yapay zeka ve blockchain çözümleri.",
|
||||||
|
keywords: [
|
||||||
|
"yazılım geliştirme",
|
||||||
|
"web tasarım",
|
||||||
|
"mobil uygulama",
|
||||||
|
"yapay zeka",
|
||||||
|
"blockchain",
|
||||||
|
"Ankara yazılım",
|
||||||
|
"ZeroSixLab",
|
||||||
|
"dijital dönüşüm",
|
||||||
|
"Ar-Ge",
|
||||||
|
"Next.js",
|
||||||
|
"React",
|
||||||
|
"TypeScript"
|
||||||
|
],
|
||||||
|
authors: [{ name: "ZeroSixLab", url: "https://zerosixlab.com" }],
|
||||||
|
creator: "ZeroSixLab",
|
||||||
|
publisher: "ZeroSixLab",
|
||||||
|
robots: {
|
||||||
|
index: true,
|
||||||
|
follow: true,
|
||||||
|
googleBot: {
|
||||||
|
index: true,
|
||||||
|
follow: true,
|
||||||
|
'max-video-preview': -1,
|
||||||
|
'max-image-preview': 'large',
|
||||||
|
'max-snippet': -1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
openGraph: {
|
||||||
|
type: "website",
|
||||||
|
locale: "tr_TR",
|
||||||
|
url: "https://zerosixlab.com",
|
||||||
|
siteName: "ZeroSixLab",
|
||||||
|
title: "ZeroSixLab - Geleceği Kodlayan Laboratuvar",
|
||||||
|
description: "Ankara merkezli, global vizyonlu yeni nesil yazılım ve Ar-Ge laboratuvarı.",
|
||||||
|
images: [
|
||||||
|
{
|
||||||
|
url: "/og-image.png",
|
||||||
|
width: 1200,
|
||||||
|
height: 630,
|
||||||
|
alt: "ZeroSixLab - Yazılım Laboratuvarı",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
twitter: {
|
||||||
|
card: "summary_large_image",
|
||||||
|
title: "ZeroSixLab - Geleceği Kodlayan Laboratuvar",
|
||||||
|
description: "Ankara merkezli, global vizyonlu yeni nesil yazılım ve Ar-Ge laboratuvarı.",
|
||||||
|
images: ["/og-image.png"],
|
||||||
|
creator: "@zerosixlab",
|
||||||
|
},
|
||||||
|
icons: {
|
||||||
|
icon: "/favicon.ico",
|
||||||
|
},
|
||||||
|
manifest: "/manifest.json",
|
||||||
|
alternates: {
|
||||||
|
canonical: "https://zerosixlab.com",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function RootLayout({
|
||||||
|
children,
|
||||||
|
}: Readonly<{
|
||||||
|
children: React.ReactNode;
|
||||||
|
}>) {
|
||||||
|
return (
|
||||||
|
<html lang="tr">
|
||||||
|
<head>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
|
||||||
|
</head>
|
||||||
|
<body className={`${inter.variable} ${orbitron.variable} font-sans bg-zsl-bg text-zsl-text`}>
|
||||||
|
{children}
|
||||||
|
<div className="scanlines"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
107
my-app/src/app/not-found.tsx
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function NotFound() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-zsl-bg flex flex-col items-center justify-center p-6 relative overflow-hidden">
|
||||||
|
{/* Background Grid */}
|
||||||
|
<div className="absolute inset-0 cyber-grid opacity-10"></div>
|
||||||
|
|
||||||
|
{/* Floating elements */}
|
||||||
|
<div className="absolute inset-0 overflow-hidden pointer-events-none">
|
||||||
|
{[...Array(10)].map((_, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className="absolute w-2 h-2 bg-zsl-primary/30 rounded-full animate-pulse"
|
||||||
|
style={{
|
||||||
|
left: `${Math.random() * 100}%`,
|
||||||
|
top: `${Math.random() * 100}%`,
|
||||||
|
animationDelay: `${Math.random() * 2}s`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Glitch Effect Text */}
|
||||||
|
<div className="relative mb-8">
|
||||||
|
<h1 className="text-[150px] md:text-[200px] font-bold font-mono text-transparent bg-clip-text bg-linear-to-r from-zsl-primary to-zsl-accent leading-none select-none">
|
||||||
|
404
|
||||||
|
</h1>
|
||||||
|
{/* Glitch layers */}
|
||||||
|
<div className="absolute inset-0 text-[150px] md:text-[200px] font-bold font-mono text-zsl-primary/20 leading-none animate-pulse select-none" style={{ transform: 'translate(2px, 2px)' }}>
|
||||||
|
404
|
||||||
|
</div>
|
||||||
|
<div className="absolute inset-0 text-[150px] md:text-[200px] font-bold font-mono text-zsl-accent/20 leading-none animate-pulse select-none" style={{ transform: 'translate(-2px, -2px)', animationDelay: '0.1s' }}>
|
||||||
|
404
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Error Message */}
|
||||||
|
<div className="text-center mb-8 relative z-10">
|
||||||
|
<h2 className="text-2xl md:text-3xl font-bold text-white mb-4">
|
||||||
|
Sayfa Bulunamadı
|
||||||
|
</h2>
|
||||||
|
<p className="text-zsl-muted max-w-md mx-auto leading-relaxed">
|
||||||
|
Aradığınız sayfa taşınmış, silinmiş veya hiç var olmamış olabilir.
|
||||||
|
Dijital evrende kaybolmuş gibisiniz.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Terminal Style Error */}
|
||||||
|
<div className="bg-zsl-card/50 border border-zsl-primary/20 rounded-xl p-6 mb-8 font-mono text-sm max-w-md w-full">
|
||||||
|
<div className="flex items-center gap-2 mb-4 pb-3 border-b border-zsl-primary/10">
|
||||||
|
<div className="w-3 h-3 rounded-full bg-red-500/80"></div>
|
||||||
|
<div className="w-3 h-3 rounded-full bg-yellow-500/80"></div>
|
||||||
|
<div className="w-3 h-3 rounded-full bg-green-500/80"></div>
|
||||||
|
<span className="ml-2 text-zsl-muted text-xs">terminal</span>
|
||||||
|
</div>
|
||||||
|
<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 className="text-red-400">Error: Page not found</div>
|
||||||
|
<div><span className="text-zsl-primary">$</span> suggest --redirect home</div>
|
||||||
|
<div className="text-zsl-accent">Suggestion: Return to homepage</div>
|
||||||
|
<div className="animate-pulse"><span className="text-zsl-primary">$</span> _</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Action Buttons */}
|
||||||
|
<div className="flex flex-wrap gap-4 justify-center">
|
||||||
|
<Link
|
||||||
|
href="/"
|
||||||
|
className="group flex items-center gap-2 px-6 py-3 bg-zsl-primary text-zsl-bg font-medium rounded-lg hover:bg-zsl-primary/90 transition-all duration-300"
|
||||||
|
>
|
||||||
|
<svg className="w-5 h-5 group-hover:-translate-x-1 transition-transform duration-300" 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>
|
||||||
|
Ana Sayfaya Dön
|
||||||
|
</Link>
|
||||||
|
<button
|
||||||
|
onClick={() => window.history.back()}
|
||||||
|
className="flex items-center gap-2 px-6 py-3 border border-zsl-primary/30 text-zsl-primary font-medium rounded-lg hover:bg-zsl-primary/10 transition-all duration-300"
|
||||||
|
>
|
||||||
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12.066 11.2a1 1 0 000 1.6l5.334 4A1 1 0 0019 16V8a1 1 0 00-1.6-.8l-5.333 4zM4.066 11.2a1 1 0 000 1.6l5.334 4A1 1 0 0011 16V8a1 1 0 00-1.6-.8l-5.334 4z" />
|
||||||
|
</svg>
|
||||||
|
Geri Git
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Decorative Elements */}
|
||||||
|
<div className="absolute bottom-8 left-8 hidden md:block">
|
||||||
|
<div className="text-xs font-mono text-zsl-muted/30">
|
||||||
|
<div>STATUS: 404</div>
|
||||||
|
<div>LOCATION: UNKNOWN</div>
|
||||||
|
<div>TIME: {new Date().toISOString()}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="absolute top-8 right-8 hidden md:block">
|
||||||
|
<div className="w-16 h-16 border border-zsl-primary/20 rounded-lg flex items-center justify-center">
|
||||||
|
<div className="w-8 h-8 border-2 border-zsl-primary/50 rounded animate-spin" style={{ animationDuration: '3s' }}></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
947
my-app/src/app/page.tsx
Normal file
@@ -0,0 +1,947 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Logo } from '@/components/Logo';
|
||||||
|
import { FeatureCard } from '@/components/FeatureCard';
|
||||||
|
import ChatInterface from '@/components/ChatInterface';
|
||||||
|
import { ScrollToTop } from '@/components/ScrollToTop';
|
||||||
|
import { LoadingScreen } from '@/components/LoadingScreen';
|
||||||
|
import { CustomCursor } from '@/components/CustomCursor';
|
||||||
|
import { ParticleBackground } from '@/components/ParticleBackground';
|
||||||
|
import { AnimatedCounter } from '@/components/AnimatedCounter';
|
||||||
|
import { TestimonialSlider } from '@/components/TestimonialSlider';
|
||||||
|
import { FAQAccordion } from '@/components/FAQAccordion';
|
||||||
|
import { PartnerLogos } from '@/components/PartnerLogos';
|
||||||
|
import { ScrollAnimation } from '@/components/ScrollAnimation';
|
||||||
|
import { CookieBanner } from '@/components/CookieBanner';
|
||||||
|
import { ProjectModal } from '@/components/ProjectModal';
|
||||||
|
import { NavPage } from '@/types';
|
||||||
|
|
||||||
|
// Data
|
||||||
|
const testimonials = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: "Ahmet Yılmaz",
|
||||||
|
role: "CEO",
|
||||||
|
company: "TechStart A.Ş.",
|
||||||
|
content: "ZeroSixLab ekibi ile çalışmak muhteşem bir deneyimdi. Projemizi zamanında ve beklentilerimizin üzerinde teslim ettiler. Özellikle yapay zeka entegrasyonları konusundaki uzmanlıkları bizi çok etkiledi.",
|
||||||
|
rating: 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: "Elif Demir",
|
||||||
|
role: "CTO",
|
||||||
|
company: "FinnoVate",
|
||||||
|
content: "Blockchain tabanlı ödeme sistemimizi geliştirirken ZeroSixLab'ın teknik derinliği ve problem çözme yetenekleri sayesinde tüm zorlukları aştık. Kesinlikle tavsiye ediyorum.",
|
||||||
|
rating: 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: "Mehmet Kaya",
|
||||||
|
role: "Kurucu",
|
||||||
|
company: "GreenEnergy",
|
||||||
|
content: "Mobil uygulamamızı ve web panelimizi sıfırdan tasarladılar. Kullanıcı deneyimi odaklı yaklaşımları ve modern teknoloji seçimleri ile projemiz büyük başarı yakaladı.",
|
||||||
|
rating: 5
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const faqItems = [
|
||||||
|
{
|
||||||
|
question: "Proje geliştirme süreci nasıl işliyor?",
|
||||||
|
answer: "Projelerimiz 5 aşamalı bir süreçten geçer: Keşif ve Analiz, Tasarım ve Prototipleme, Geliştirme, Test ve QA, son olarak da Lansman ve Destek. Her aşamada sizinle düzenli iletişim halinde kalarak projenin doğru yönde ilerlediğinden emin oluyoruz."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Hangi teknolojilerle çalışıyorsunuz?",
|
||||||
|
answer: "Modern web teknolojileri (React, Next.js, Vue.js), mobil geliştirme (Flutter, React Native, Swift, Kotlin), backend sistemleri (Node.js, Python, Go, Rust), bulut platformları (AWS, GCP, Azure) ve yapay zeka/makine öğrenmesi (TensorFlow, PyTorch, OpenAI API) dahil geniş bir teknoloji yelpazesiyle çalışıyoruz."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Proje maliyeti nasıl belirleniyor?",
|
||||||
|
answer: "Proje maliyeti; kapsam, karmaşıklık, zaman çizelgesi ve kullanılacak teknolojilere göre belirlenir. Ücretsiz keşif görüşmemizde ihtiyaçlarınızı detaylı analiz ederek size özel bir teklif sunuyoruz. Sabit fiyat veya zaman/materyal bazlı çalışma modellerinden birini tercih edebilirsiniz."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Proje teslim süreleri ne kadar?",
|
||||||
|
answer: "Basit bir web sitesi 2-4 hafta, orta ölçekli bir uygulama 2-3 ay, büyük ölçekli kurumsal projeler ise 4-8 ay sürebilir. MVP (Minimum Uygulanabilir Ürün) yaklaşımıyla hızlı bir şekilde pazara çıkmanızı sağlayabilir, ardından iteratif geliştirmelerle ürününüzü büyütebiliriz."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Proje sonrası destek sağlıyor musunuz?",
|
||||||
|
answer: "Evet! Tüm projelerimize lansman sonrası 3 ay ücretsiz destek sağlıyoruz. Ayrıca uzun vadeli bakım ve geliştirme anlaşmaları, 7/24 teknik destek ve SLA garantili hizmet paketleri sunuyoruz."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Uzaktan çalışıyor musunuz?",
|
||||||
|
answer: "Evet, tamamen uzaktan çalışabiliyoruz. Slack, Notion, Jira gibi modern proje yönetim araçları ve düzenli video görüşmelerle lokasyon fark etmeksizin etkili bir şekilde çalışıyoruz. Ankara'da iseniz yüz yüze toplantılar da düzenleyebiliriz."
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const partners = [
|
||||||
|
{ name: "TechCorp" },
|
||||||
|
{ name: "InnovateTR" },
|
||||||
|
{ name: "CloudFirst" },
|
||||||
|
{ name: "DataDriven" },
|
||||||
|
{ name: "AILabs" },
|
||||||
|
{ name: "SecureNet" },
|
||||||
|
{ name: "FinTech+" },
|
||||||
|
{ name: "SmartCity" }
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
const [currentPage, setCurrentPage] = useState<NavPage>(NavPage.HOME);
|
||||||
|
const [scrolled, setScrolled] = useState(false);
|
||||||
|
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||||
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const [selectedProject, setSelectedProject] = useState<any>(null);
|
||||||
|
const [isProjectModalOpen, setIsProjectModalOpen] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleScroll = () => {
|
||||||
|
setScrolled(window.scrollY > 20);
|
||||||
|
};
|
||||||
|
window.addEventListener('scroll', handleScroll);
|
||||||
|
|
||||||
|
// Loading screen timer
|
||||||
|
const loadingTimer = setTimeout(() => setIsLoading(false), 2500);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('scroll', handleScroll);
|
||||||
|
clearTimeout(loadingTimer);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleNavClick = (page: NavPage) => {
|
||||||
|
setCurrentPage(page);
|
||||||
|
setIsMobileMenuOpen(false);
|
||||||
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleProjectClick = (project: any) => {
|
||||||
|
setSelectedProject(project);
|
||||||
|
setIsProjectModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const TechStackMarquee = () => {
|
||||||
|
const techs = [
|
||||||
|
"REACT", "PYTHON", "AWS", "FLUTTER", "TENSORFLOW", "DOCKER", "KUBERNETES",
|
||||||
|
"NODE.JS", "TYPESCRIPT", "GO", "RUST", "OPENAI", "GEMINI", "POSTGRESQL",
|
||||||
|
"MONGODB", "REDIS", "GRAPHQL", "NEXT.JS", "TAILWINDCSS", "FIGMA", "LINUX",
|
||||||
|
"GIT", "JENKINS", "TERRAFORM", "ANSIBLE", "C++", "C#", "AZURE",
|
||||||
|
"GOOGLE CLOUD", "ANDROID", "IOS", "SOLIDITY", "WEB3", "KAFKA", "ELASTICSEARCH"
|
||||||
|
];
|
||||||
|
// Duplicate for seamless loop
|
||||||
|
const allTechs = [...techs, ...techs, ...techs];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="max-w-[100vw] mt-10 mb-20 border-y border-white/5 py-6 overflow-hidden relative group bg-black/20 backdrop-blur-sm">
|
||||||
|
<div className="absolute inset-y-0 left-0 w-20 bg-linear-to-r from-zsl-bg to-transparent z-10"></div>
|
||||||
|
<div className="absolute inset-y-0 right-0 w-20 bg-linear-to-l from-zsl-bg to-transparent z-10"></div>
|
||||||
|
<div className="flex animate-scroll hover:[animation-play-state:paused] w-max">
|
||||||
|
{allTechs.map((tech, index) => (
|
||||||
|
<span key={index} className="mx-6 font-mono text-lg font-bold text-slate-600 hover:text-zsl-primary transition-colors cursor-default select-none flex items-center gap-2">
|
||||||
|
<span className="w-1.5 h-1.5 bg-zsl-accent/50 rounded-full"></span>
|
||||||
|
{tech}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderContent = () => {
|
||||||
|
switch (currentPage) {
|
||||||
|
case NavPage.LAB:
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen pt-32 px-4 pb-20 max-w-7xl mx-auto animate-in fade-in duration-700">
|
||||||
|
<div className="text-center mb-10">
|
||||||
|
<h2 className="font-mono text-4xl font-bold text-white mb-4">ZeroSixLab <span className="text-zsl-primary">AI</span></h2>
|
||||||
|
<p className="text-zsl-muted">Yapay zeka destekli asistanımız ile projelerinizi tartışın.</p>
|
||||||
|
</div>
|
||||||
|
<ChatInterface />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
case NavPage.ABOUT:
|
||||||
|
const teamMembers = [
|
||||||
|
{
|
||||||
|
name: "Şahan Hasret",
|
||||||
|
handle: "ROOT_ACCESS",
|
||||||
|
role: "Full Stack & Cyber Security",
|
||||||
|
color: "primary",
|
||||||
|
desc: "Sistemin mimarı. Hem kodu hem güvenliği yöneten ana merkez.",
|
||||||
|
stats: { code: 99, security: 100, sleep: 10 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Baran Hasret",
|
||||||
|
handle: "MECH_MIND",
|
||||||
|
role: "Dev & Mechatronics",
|
||||||
|
color: "accent",
|
||||||
|
desc: "Yazılımı fiziksel dünya ile birleştiren mekatronik uzmanı.",
|
||||||
|
stats: { hardware: 95, logic: 98, robotics: 100 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Yiğit Demiralp",
|
||||||
|
handle: "SYS_ARCHITECT",
|
||||||
|
role: "System Engineer",
|
||||||
|
color: "primary",
|
||||||
|
desc: "Altyapının ve sistemlerin kesintisiz çalışmasını sağlayan mühendis.",
|
||||||
|
stats: { uptime: 99, cloud: 95, scale: 90 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sinan Aydın",
|
||||||
|
handle: "GATEKEEPER",
|
||||||
|
role: "System Engineer",
|
||||||
|
color: "accent",
|
||||||
|
desc: "Karmaşık sistem ağlarını ve sunucu yapılarını yöneten mimar.",
|
||||||
|
stats: { network: 98, devops: 94, latency: 1 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fatma Şahiner",
|
||||||
|
handle: "ALGORITHM",
|
||||||
|
role: "Software Developer",
|
||||||
|
color: "primary",
|
||||||
|
desc: "Temiz kod prensipleriyle çalışan güçlü algoritma geliştiricisi.",
|
||||||
|
stats: { java: 90, backend: 95, bugs: 0 }
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen pt-32 px-4 pb-20 max-w-7xl mx-auto animate-in slide-in-from-bottom-5 duration-700">
|
||||||
|
|
||||||
|
{/* Story Section */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-12 items-center mb-32">
|
||||||
|
<div className="order-2 md:order-1 space-y-6">
|
||||||
|
<div 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-2">BİZ KİMİZ?</div>
|
||||||
|
<h2 className="font-mono text-4xl md:text-5xl font-bold text-white leading-tight">
|
||||||
|
Profesyonel <span className="text-zsl-primary">Mühendislik</span>,<br/>
|
||||||
|
Yaratıcı <span className="text-zsl-accent">Çözümler.</span>
|
||||||
|
</h2>
|
||||||
|
<div className="w-20 h-1 bg-linear-to-r from-zsl-primary to-zsl-accent"></div>
|
||||||
|
<div className="text-zsl-text space-y-4 leading-relaxed text-lg font-light">
|
||||||
|
<p>
|
||||||
|
ZeroSixLab, Ankara merkezli kurulan ancak vizyonu global standartlarda teknoloji üretmek olan yeni nesil bir yazılım ve Ar-Ge merkezidir. Amacımız, karmaşık iş problemlerini en güncel teknolojileri kullanarak yalın, güçlü ve ölçeklenebilir dijital çözümlere dönüştürmektir.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Bizim için yazılım geliştirme, sadece kod yazmak değil; yaşayan, gelişen ve değer üreten sistemler kurgulamaktır. Mühendislik disiplinini yaratıcı düşünceyle harmanlayan uzman ekibimiz, her projeye bir laboratuvar titizliğiyle yaklaşır ve operasyonel mükemmelliği hedefler.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
İsmimizdeki "06", kodlarımızın doğum yeri olan Başkent Ankara'yı ve köklerimizi; "Lab" ise teknolojiyi bir bilim olarak ele alan Ar-Ge yaklaşımımızı simgeler. Müşterilerimizi sadece hizmet verdiğimiz kurumlar olarak değil, dijital geleceği birlikte tasarladığımız stratejik ortaklarımız olarak görüyoruz.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Manifesto Grid */}
|
||||||
|
<div className="grid grid-cols-2 gap-4 mt-6">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-2 h-2 bg-zsl-primary rounded-full"></div>
|
||||||
|
<span className="font-mono text-sm text-white">Analitik Yaklaşım</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-2 h-2 bg-zsl-accent rounded-full"></div>
|
||||||
|
<span className="font-mono text-sm text-white">Sürekli İnovasyon</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-2 h-2 bg-zsl-accent rounded-full"></div>
|
||||||
|
<span className="font-mono text-sm text-white">Yüksek Performans</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-2 h-2 bg-zsl-primary rounded-full"></div>
|
||||||
|
<span className="font-mono text-sm text-white">Global Standartlar</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div className="order-1 md:order-2 flex justify-center relative">
|
||||||
|
{/* Holographic Decoration */}
|
||||||
|
<div className="absolute inset-0 bg-zsl-primary/5 rounded-full blur-[100px] animate-pulse-slow"></div>
|
||||||
|
<div className="relative w-80 h-80 rounded-full border-2 border-dashed border-zsl-primary/30 flex items-center justify-center bg-black/40 backdrop-blur-sm">
|
||||||
|
<div className="absolute inset-0 border border-zsl-primary/10 rounded-full animate-[spin_20s_linear_infinite]"></div>
|
||||||
|
<div className="absolute inset-4 border border-zsl-accent/10 rounded-full animate-[spin_15s_linear_infinite_reverse]"></div>
|
||||||
|
<Logo size="lg" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Team Section */}
|
||||||
|
<div className="mb-20">
|
||||||
|
<div className="text-center mb-16">
|
||||||
|
<h3 className="font-mono text-3xl font-bold text-white mb-2">Uzman Kadromuz</h3>
|
||||||
|
<p className="text-zsl-muted">Projelerinize değer katan mühendis ve geliştiriciler.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-4">
|
||||||
|
{teamMembers.map((member, idx) => (
|
||||||
|
<div key={idx} className="group relative bg-zsl-card/40 border border-white/5 rounded-xl overflow-hidden hover:border-white/20 transition-all duration-300">
|
||||||
|
{/* Card Header / Avatar Placeholder */}
|
||||||
|
<div className={`h-28 bg-linear-to-b ${member.color === 'primary' ? 'from-zsl-primary/20' : 'from-zsl-accent/20'} to-transparent flex items-center justify-center relative`}>
|
||||||
|
<div className="absolute inset-0 cyber-grid opacity-20"></div>
|
||||||
|
<div className={`w-16 h-16 rounded-lg border-2 ${member.color === 'primary' ? 'border-zsl-primary bg-zsl-primary/20' : 'border-zsl-accent bg-zsl-accent/20'} flex items-center justify-center shadow-[0_0_20px_rgba(0,0,0,0.5)] backdrop-blur-md z-10 group-hover:scale-110 transition-transform duration-300`}>
|
||||||
|
<span className="font-mono text-xl font-bold text-white">{member.name.charAt(0)}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Card Body */}
|
||||||
|
<div className="p-4 text-center relative">
|
||||||
|
<div className={`absolute top-0 left-1/2 -translate-x-1/2 -translate-y-1/2 text-[8px] font-mono font-bold px-2 py-0.5 rounded bg-black border ${member.color === 'primary' ? 'border-zsl-primary text-zsl-primary' : 'border-zsl-accent text-zsl-accent'} uppercase tracking-wider whitespace-nowrap`}>
|
||||||
|
{member.handle}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4 className="text-base font-bold text-white mt-3">{member.name}</h4>
|
||||||
|
<p className="text-zsl-muted text-[8px] font-mono uppercase tracking-widest mb-3">{member.role}</p>
|
||||||
|
<p className="text-slate-400 text-xs mb-4 min-h-10 line-clamp-3">{member.desc}</p>
|
||||||
|
|
||||||
|
{/* Stats */}
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
{Object.entries(member.stats).map(([key, val]) => (
|
||||||
|
<div key={key} className="flex items-center gap-1.5 text-[8px] font-mono uppercase text-slate-500">
|
||||||
|
<span className="w-14 text-right truncate">{key}</span>
|
||||||
|
<div className="flex-1 h-1 bg-slate-800 rounded-full overflow-hidden">
|
||||||
|
<div className={`h-full ${member.color === 'primary' ? 'bg-zsl-primary' : 'bg-zsl-accent'}`} style={{ width: `${val}%` }}></div>
|
||||||
|
</div>
|
||||||
|
<span className="w-5 text-right text-white">{val}%</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Join Community CTA */}
|
||||||
|
<div className="rounded-2xl border border-zsl-primary/30 bg-linear-to-r from-zsl-card to-zsl-bg p-12 text-center relative overflow-hidden group">
|
||||||
|
<div className="absolute inset-0 cyber-grid opacity-20 animate-grid-move"></div>
|
||||||
|
<div className="relative z-10">
|
||||||
|
<h3 className="text-3xl font-mono font-bold text-white mb-4">Geleceği Birlikte Tasarlayalım</h3>
|
||||||
|
<p className="text-zsl-muted max-w-2xl mx-auto mb-8">
|
||||||
|
Projelerimizde yer almak, açık kaynak kütüphanelerimize katkıda bulunmak veya teknoloji üzerine fikir alışverişi yapmak için topluluğumuza katılın.
|
||||||
|
</p>
|
||||||
|
<div className="flex justify-center gap-4">
|
||||||
|
<button className="px-6 py-3 bg-[#5865F2] hover:bg-[#4752C4] text-white font-bold rounded flex items-center gap-2 transition-all hover:scale-105">
|
||||||
|
<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.086 2.157 2.419 0 1.334-.956 2.42-2.157 2.42zm7.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.086 2.157 2.419 0 1.334-.946 2.42-2.157 2.42z"/></svg>
|
||||||
|
Discord
|
||||||
|
</button>
|
||||||
|
<button className="px-6 py-3 bg-[#333] hover:bg-[#222] text-white font-bold rounded flex items-center gap-2 transition-all hover:scale-105 border border-white/20">
|
||||||
|
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
|
||||||
|
GitHub
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
case NavPage.BLOG:
|
||||||
|
const blogs = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: "Sıfır Güven Mimarisi (Zero Trust) Nedir?",
|
||||||
|
category: "Security",
|
||||||
|
date: "2024.05.15",
|
||||||
|
readTime: "5 min read",
|
||||||
|
excerpt: "Geleneksel 'kale ve hendek' güvenlik modelleri artık yeterli değil. Modern altyapıda 'asla güvenme, her zaman doğrula' prensibini nasıl uygularsınız?",
|
||||||
|
image: "https://images.unsplash.com/photo-1550751827-4bd374c3f58b?q=80&w=2070&auto=format&fit=crop"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
title: "React 19: Compiler ve Server Actions",
|
||||||
|
category: "Frontend",
|
||||||
|
date: "2024.05.10",
|
||||||
|
readTime: "8 min read",
|
||||||
|
excerpt: "React ekosistemindeki en büyük paradigma değişikliği kapıda. useOptimistic, useFormStatus ve otomatik memoization geliştirici deneyimini nasıl değiştirecek?",
|
||||||
|
image: "https://images.unsplash.com/photo-1633356122544-f134324a6cee?q=80&w=2070&auto=format&fit=crop"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
title: "Yapay Zeka ile Kodlama: Dost mu Düşman mı?",
|
||||||
|
category: "AI",
|
||||||
|
date: "2024.04.28",
|
||||||
|
readTime: "6 min read",
|
||||||
|
excerpt: "Copilot ve Gemini gibi araçlar junior geliştiricileri işsiz mi bırakacak yoksa onları süper üretken mühendislere mi dönüştürecek?",
|
||||||
|
image: "https://images.unsplash.com/photo-1620712943543-bcc4688e7485?q=80&w=1965&auto=format&fit=crop"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen pt-32 px-4 pb-20 max-w-7xl mx-auto animate-in fade-in duration-700">
|
||||||
|
{/* Header Terminal Style */}
|
||||||
|
<div className="border-b border-white/10 pb-8 mb-12">
|
||||||
|
<div className="font-mono text-xs text-zsl-muted mb-2">root@zerosixlab:~/logs$ fetch --latest</div>
|
||||||
|
<h2 className="text-4xl md:text-5xl font-mono font-bold text-white mb-4">Lab <span className="text-zsl-primary">Notları</span></h2>
|
||||||
|
<p className="text-zsl-muted max-w-2xl text-lg">
|
||||||
|
Teknoloji, yazılım mimarisi ve siber güvenlik üzerine teknik incelemelerimiz ve Ar-Ge çıktılarımız.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Featured Post */}
|
||||||
|
<div className="mb-16 group cursor-pointer relative rounded-2xl overflow-hidden border border-zsl-primary/20 bg-zsl-card hover:border-zsl-primary/50 transition-all duration-500">
|
||||||
|
<div className="absolute inset-0 bg-linear-to-r from-black via-black/80 to-transparent z-10"></div>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2">
|
||||||
|
<div className="p-8 md:p-12 relative z-20 flex flex-col justify-center h-full">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<span className="px-2 py-1 bg-zsl-primary/10 border border-zsl-primary/30 text-zsl-primary text-xs font-mono rounded">AI & RESEARCH</span>
|
||||||
|
<span className="text-zsl-muted text-xs font-mono">2024.05.20</span>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-3xl font-bold text-white mb-4 group-hover:text-zsl-primary transition-colors">LLM Modellerini Fine-Tune Etmek: Ankara Veri Seti Deneyimi</h3>
|
||||||
|
<p className="text-slate-400 mb-6 leading-relaxed">
|
||||||
|
Standart dil modelleri genel kültürde iyidir, peki ya yerel mevzuata veya sektörel jargona hakim olmaları gerekirse? Kendi veri setimizi oluştururken öğrendiğimiz 5 kritik ders.
|
||||||
|
</p>
|
||||||
|
<div className="flex items-center gap-2 text-white font-mono text-sm group-hover:translate-x-2 transition-transform">
|
||||||
|
<span>Okumaya Başla</span>
|
||||||
|
<span className="text-zsl-primary">→</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="h-64 md:h-auto relative overflow-hidden">
|
||||||
|
<img
|
||||||
|
src="https://images.unsplash.com/photo-1655720828018-edd2daec9349?q=80&w=2064&auto=format&fit=crop"
|
||||||
|
alt="AI Neural Network"
|
||||||
|
className="w-full h-full object-cover opacity-60 group-hover:opacity-100 group-hover:scale-105 transition-all duration-700"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Blog Grid */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||||
|
{blogs.map((blog) => (
|
||||||
|
<div key={blog.id} className="group flex flex-col h-full bg-black/20 border border-white/10 rounded-xl overflow-hidden hover:border-zsl-accent/50 hover:bg-zsl-card/40 transition-all duration-300 shadow-lg">
|
||||||
|
<div className="h-52 relative overflow-hidden border-b border-white/5">
|
||||||
|
<img
|
||||||
|
src={blog.image}
|
||||||
|
alt={blog.title}
|
||||||
|
className="w-full h-full object-cover transform group-hover:scale-110 transition-transform duration-700"
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 bg-black/40 group-hover:bg-transparent transition-colors duration-300"></div>
|
||||||
|
<div className="absolute top-4 left-4">
|
||||||
|
<span className={`px-2 py-1 text-[10px] font-mono font-bold border rounded uppercase tracking-wider backdrop-blur-md ${
|
||||||
|
blog.category === 'Security' ? 'border-red-500/50 text-red-100 bg-red-900/40' :
|
||||||
|
blog.category === 'Frontend' ? 'border-blue-500/50 text-blue-100 bg-blue-900/40' :
|
||||||
|
'border-purple-500/50 text-purple-100 bg-purple-900/40'
|
||||||
|
}`}>
|
||||||
|
{blog.category}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="p-6 flex-1 flex flex-col">
|
||||||
|
<div className="flex justify-between items-center mb-3">
|
||||||
|
<span className="text-xs font-mono text-zsl-muted">{blog.date}</span>
|
||||||
|
<span className="text-xs font-mono text-zsl-muted">{blog.readTime}</span>
|
||||||
|
</div>
|
||||||
|
<h4 className="text-xl font-bold text-white mb-3 group-hover:text-zsl-accent transition-colors">{blog.title}</h4>
|
||||||
|
<p className="text-sm text-slate-400 leading-relaxed mb-6 flex-1">{blog.excerpt}</p>
|
||||||
|
<a href="#" className="inline-flex items-center gap-2 text-xs font-mono font-bold text-white uppercase tracking-widest hover:text-zsl-accent transition-colors">
|
||||||
|
Kaydı İncele <span className="text-lg leading-none">›</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
case NavPage.SERVICES:
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen pt-32 px-4 pb-20 max-w-7xl mx-auto animate-in fade-in duration-700">
|
||||||
|
<div className="text-center mb-16 relative">
|
||||||
|
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-96 h-96 bg-white/5 rounded-full blur-3xl -z-10"></div>
|
||||||
|
<h2 className="font-mono text-4xl font-bold text-white mb-4">Uzmanlık Alanları</h2>
|
||||||
|
<p className="text-zsl-muted text-lg max-w-2xl mx-auto">Biz her işi yapmayız. Sadece en iyi olduğumuz, geleceği şekillendiren teknolojilere odaklanırız.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
<FeatureCard
|
||||||
|
title="Web & Mobil Geliştirme"
|
||||||
|
description="React, Node.js ve Flutter ile yüksek performanslı, ölçeklenebilir uygulamalar. Sadece kod yazmıyor, platform inşa ediyoruz."
|
||||||
|
icon={<svg className="w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z" /></svg>}
|
||||||
|
accentColor="primary"
|
||||||
|
/>
|
||||||
|
<FeatureCard
|
||||||
|
title="Özel Yazılım Çözümleri"
|
||||||
|
description="Şirketinize özel CRM, ERP ve Otomasyon sistemleri. Karmaşık iş süreçlerinizi dijitalleştirip basitleştiriyoruz."
|
||||||
|
icon={<svg className="w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" /></svg>}
|
||||||
|
accentColor="accent"
|
||||||
|
/>
|
||||||
|
<FeatureCard
|
||||||
|
title="AI & Veri Analitiği"
|
||||||
|
description="Yapay zeka entegrasyonları ile verilerinizi anlamlandırıyor, geleceği tahmin eden algoritmalar geliştiriyoruz."
|
||||||
|
icon={<svg className="w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" /></svg>}
|
||||||
|
accentColor="primary"
|
||||||
|
/>
|
||||||
|
<FeatureCard
|
||||||
|
title="UI/UX Tasarım"
|
||||||
|
description="Kullanıcı odaklı, estetik ve işlevsel arayüzler. Teknolojinin soğuk yüzünü insan dostu tasarımlarla ısıtıyoruz."
|
||||||
|
icon={<svg className="w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" /></svg>}
|
||||||
|
accentColor="accent"
|
||||||
|
/>
|
||||||
|
<FeatureCard
|
||||||
|
title="Danışmanlık"
|
||||||
|
description="Dijital dönüşüm yolculuğunuzda teknik rehberlik. Hangi teknolojiyi nerede kullanmanız gerektiğini analiz ediyoruz."
|
||||||
|
icon={<svg className="w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"><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>}
|
||||||
|
accentColor="primary"
|
||||||
|
/>
|
||||||
|
<FeatureCard
|
||||||
|
title="Siber Güvenlik"
|
||||||
|
description="Uygulamalarınızın ve verilerinizin güvenliğini en başından (Shift-Left) tasarlıyoruz."
|
||||||
|
icon={<svg className="w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" /></svg>}
|
||||||
|
accentColor="accent"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
case NavPage.PROJECTS:
|
||||||
|
const projects = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: "NovaCore: Bankacılık Otomasyonu",
|
||||||
|
type: "Fintech",
|
||||||
|
date: "Q3 2023",
|
||||||
|
problem: "Eski sistemlerin yavaşlığı nedeniyle kredi onay süreçlerinin 48 saati bulması.",
|
||||||
|
solution: "Mikroservis mimarisi ve AI destekli belge okuma (OCR) modülü geliştirildi.",
|
||||||
|
tags: ['Python', 'React', 'AWS', 'TensorFlow', 'PostgreSQL'],
|
||||||
|
accent: 'primary',
|
||||||
|
image: "https://images.unsplash.com/photo-1611974765270-ca1258634369?q=80&w=2064&auto=format&fit=crop"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
title: "LogiTrack: Akıllı Lojistik Platformu",
|
||||||
|
type: "Logistics",
|
||||||
|
date: "Q1 2024",
|
||||||
|
problem: "Dağıtım ağındaki araçların rotalama verimsizliği ve yakıt israfı.",
|
||||||
|
solution: "Genetik algoritmalarla çalışan dinamik rota optimizasyon motoru.",
|
||||||
|
tags: ['Flutter', 'Google Maps API', 'Node.js', 'Redis', 'Docker'],
|
||||||
|
accent: 'accent',
|
||||||
|
image: "https://images.unsplash.com/photo-1580674285054-bed31e145f59?q=80&w=2070&auto=format&fit=crop"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
title: "VitalSync: Uzaktan Hasta Takibi",
|
||||||
|
type: "HealthTech",
|
||||||
|
date: "Q4 2023",
|
||||||
|
problem: "Kronik hastaların verilerinin hastaneye anlık ulaşmaması.",
|
||||||
|
solution: "IoT entegrasyonlu, uçtan uca şifreli mobil veri toplama sistemi.",
|
||||||
|
tags: ['React Native', 'Go', 'Kubernetes', 'Azure', 'WebRTC'],
|
||||||
|
accent: 'primary',
|
||||||
|
image: "https://images.unsplash.com/photo-1576091160550-217358c7e618?q=80&w=2070&auto=format&fit=crop"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen pt-32 px-4 pb-20 max-w-7xl mx-auto">
|
||||||
|
<div className="text-center mb-16">
|
||||||
|
<h2 className="font-mono text-4xl font-bold text-white mb-4">Laboratuvar Sonuçları</h2>
|
||||||
|
<p className="text-zsl-muted text-lg">Teoriyi pratiğe döktüğümüz gerçek vaka analizleri.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-16">
|
||||||
|
{projects.map((project, index) => (
|
||||||
|
<div key={project.id} className={`bg-zsl-card border border-zsl-primary/20 rounded-2xl overflow-hidden hover:shadow-[0_0_30px_rgba(0,0,0,0.5)] transition-all group ${index % 2 !== 0 ? 'md:flex-row-reverse' : ''} flex flex-col md:flex-row`}>
|
||||||
|
<div className="p-8 md:p-12 space-y-8 flex flex-col justify-center md:w-1/2">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className={`font-mono text-xs tracking-widest uppercase px-2 py-1 rounded border ${project.accent === 'primary' ? 'text-zsl-primary border-zsl-primary/20 bg-zsl-primary/10' : 'text-zsl-accent border-zsl-accent/20 bg-zsl-accent/10'}`}>
|
||||||
|
{project.type}
|
||||||
|
</span>
|
||||||
|
<span className="w-1 h-1 bg-slate-500 rounded-full"></span>
|
||||||
|
<span className="text-slate-400 text-sm font-mono">{project.date}</span>
|
||||||
|
</div>
|
||||||
|
<h3 className={`text-3xl font-mono font-bold text-white group-hover:${project.accent === 'primary' ? 'text-zsl-primary' : 'text-zsl-accent'} transition-colors`}>{project.title}</h3>
|
||||||
|
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="border-l-2 border-slate-700 pl-4">
|
||||||
|
<h4 className="text-slate-400 font-bold text-xs uppercase mb-1 tracking-wider">Sorun</h4>
|
||||||
|
<p className="text-zsl-text text-sm leading-relaxed">{project.problem}</p>
|
||||||
|
</div>
|
||||||
|
<div className={`border-l-2 ${project.accent === 'primary' ? 'border-zsl-primary' : 'border-zsl-accent'} pl-4`}>
|
||||||
|
<h4 className={`${project.accent === 'primary' ? 'text-zsl-primary' : 'text-zsl-accent'} font-bold text-xs uppercase mb-1 tracking-wider`}>Çözüm</h4>
|
||||||
|
<p className="text-white text-sm leading-relaxed">{project.solution}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="pt-4 flex gap-3 flex-wrap">
|
||||||
|
{project.tags.map((tag) => (
|
||||||
|
<span key={tag} className="px-3 py-1 bg-slate-800 rounded text-xs text-slate-300 border border-slate-700 hover:border-white hover:text-white transition-colors cursor-default select-none">{tag}</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Visual Area */}
|
||||||
|
<div className="bg-black/50 relative flex items-center justify-center p-8 md:w-1/2 min-h-75 overflow-hidden">
|
||||||
|
{/* Abstract BG */}
|
||||||
|
<div className={`absolute inset-0 bg-linear-to-br ${project.accent === 'primary' ? 'from-zsl-primary/10' : 'from-zsl-accent/10'} to-transparent opacity-50`}></div>
|
||||||
|
<div className="absolute inset-0 cyber-grid opacity-30"></div>
|
||||||
|
|
||||||
|
{/* Card Visualization */}
|
||||||
|
<div className="w-full max-w-sm aspect-video bg-zsl-card/90 rounded-lg border border-slate-700 relative overflow-hidden shadow-2xl transform group-hover:scale-105 transition-transform duration-700 flex flex-col">
|
||||||
|
{/* Browser Header */}
|
||||||
|
<div className="h-8 bg-slate-800 flex items-center px-3 gap-2 border-b border-slate-700 z-10 relative">
|
||||||
|
<div className="w-2.5 h-2.5 rounded-full bg-red-500"></div>
|
||||||
|
<div className="w-2.5 h-2.5 rounded-full bg-yellow-500"></div>
|
||||||
|
<div className="w-2.5 h-2.5 rounded-full bg-green-500"></div>
|
||||||
|
<div className="ml-2 w-full h-4 bg-slate-700 rounded-full opacity-30"></div>
|
||||||
|
</div>
|
||||||
|
{/* Browser Body with Image */}
|
||||||
|
<div className="flex-1 relative bg-slate-900 group-hover:filter-none filter grayscale transition-all duration-700">
|
||||||
|
<img src={project.image} alt={project.title} className="absolute inset-0 w-full h-full object-cover opacity-80 group-hover:opacity-100 transition-opacity" />
|
||||||
|
<div className="absolute inset-0 bg-linear-to-t from-black/80 to-transparent"></div>
|
||||||
|
|
||||||
|
{/* Floating Code Snippet Effect Overlay */}
|
||||||
|
<div className="absolute bottom-4 right-4 font-mono text-[8px] text-slate-300 bg-black/60 p-2 rounded border border-slate-600 backdrop-blur-sm shadow-lg">
|
||||||
|
{`status: "DEPLOYED"\nuptime: "99.9%"`}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
case NavPage.CONTACT:
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen pt-32 px-4 pb-20 max-w-4xl mx-auto">
|
||||||
|
<div className="bg-zsl-card/80 border border-zsl-primary/20 rounded-2xl p-8 md:p-12 shadow-2xl relative overflow-hidden backdrop-blur-xl">
|
||||||
|
<div className="absolute top-0 right-0 -mt-10 -mr-10 w-40 h-40 bg-zsl-accent/10 rounded-full blur-3xl"></div>
|
||||||
|
<div className="absolute bottom-0 left-0 -mb-10 -ml-10 w-40 h-40 bg-zsl-primary/10 rounded-full blur-3xl"></div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-4 mb-2">
|
||||||
|
<div className="w-10 h-1 bg-zsl-primary"></div>
|
||||||
|
<h2 className="font-mono text-3xl font-bold text-white">Proje Başlat</h2>
|
||||||
|
</div>
|
||||||
|
<p className="text-zsl-muted mb-8 pl-14">Fikrinizi gerçeğe dönüştürmek için laboratuvara veri girişi yapın.</p>
|
||||||
|
|
||||||
|
<form className="space-y-6 relative z-10" onSubmit={(e) => e.preventDefault()}>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-xs font-mono text-zsl-primary uppercase tracking-wider">Ad Soyad / Şirket</label>
|
||||||
|
<input type="text" className="w-full bg-black/30 border border-slate-700 rounded-lg px-4 py-3 text-white focus:border-zsl-primary focus:outline-none focus:ring-1 focus:ring-zsl-primary transition-all placeholder-slate-600" placeholder="John Doe" />
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-xs font-mono text-zsl-primary uppercase tracking-wider">İletişim Kanalı (Email)</label>
|
||||||
|
<input type="email" className="w-full bg-black/30 border border-slate-700 rounded-lg px-4 py-3 text-white focus:border-zsl-primary focus:outline-none focus:ring-1 focus:ring-zsl-primary transition-all placeholder-slate-600" placeholder="ornek@sirket.com" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-xs font-mono text-zsl-primary uppercase tracking-wider">Proje Türü</label>
|
||||||
|
<div className="relative">
|
||||||
|
<select className="w-full bg-black/30 border border-slate-700 rounded-lg px-4 py-3 text-white focus:border-zsl-primary focus:outline-none transition-all appearance-none cursor-pointer">
|
||||||
|
<option>Web Uygulaması</option>
|
||||||
|
<option>Mobil Uygulama</option>
|
||||||
|
<option>Özel Yazılım / Otomasyon</option>
|
||||||
|
<option>Yapay Zeka Entegrasyonu</option>
|
||||||
|
<option>Diğer</option>
|
||||||
|
</select>
|
||||||
|
<div className="absolute right-4 top-1/2 -translate-y-1/2 pointer-events-none text-zsl-primary">▼</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-xs font-mono text-zsl-primary uppercase tracking-wider">Yatırım Ölçeği (Bütçe)</label>
|
||||||
|
<div className="grid grid-cols-3 gap-4">
|
||||||
|
<button className="border border-slate-700 bg-black/20 rounded-lg py-3 text-sm text-slate-400 hover:border-zsl-primary hover:text-white transition-all">Startup</button>
|
||||||
|
<button className="border border-zsl-accent bg-zsl-accent/10 rounded-lg py-3 text-sm text-zsl-accent font-bold shadow-[0_0_10px_rgba(255,170,0,0.1)]">Growth</button>
|
||||||
|
<button className="border border-slate-700 bg-black/20 rounded-lg py-3 text-sm text-slate-400 hover:border-zsl-primary hover:text-white transition-all">Enterprise</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-xs font-mono text-zsl-primary uppercase tracking-wider">Proje Detayları</label>
|
||||||
|
<textarea className="w-full bg-black/30 border border-slate-700 rounded-lg px-4 py-3 text-white focus:border-zsl-primary focus:outline-none focus:ring-1 focus:ring-zsl-primary transition-all h-32" placeholder="Hedeflerinizden ve vizyonunuzdan bahsedin..."></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button className="w-full bg-linear-to-r from-zsl-primary to-blue-600 hover:to-blue-500 text-black font-bold font-mono py-4 rounded-lg transform hover:scale-[1.01] transition-all shadow-[0_0_20px_rgba(0,212,255,0.3)] tracking-widest text-lg">
|
||||||
|
SİNYAL GÖNDER
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
case NavPage.HOME:
|
||||||
|
default:
|
||||||
|
return (
|
||||||
|
<div className="pt-24 pb-12 px-4 relative overflow-hidden">
|
||||||
|
{/* Cyber Grid Background Effect */}
|
||||||
|
<div className="absolute inset-0 cyber-grid animate-grid-move -z-10 opacity-30"></div>
|
||||||
|
|
||||||
|
{/* Hero Section */}
|
||||||
|
<div className="max-w-7xl mx-auto text-center py-24 relative z-10">
|
||||||
|
{/* Background decorative elements */}
|
||||||
|
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-150 h-150 bg-zsl-primary/5 rounded-full blur-[120px] -z-10 animate-pulse-slow"></div>
|
||||||
|
|
||||||
|
<div className="inline-flex items-center gap-2 mb-8 px-4 py-1.5 rounded-full bg-zsl-primary/5 border border-zsl-primary/20 backdrop-blur-sm animate-in fade-in slide-in-from-top-4 duration-700">
|
||||||
|
<span className="w-2 h-2 rounded-full bg-zsl-primary animate-pulse"></span>
|
||||||
|
<span className="text-zsl-primary font-mono text-xs tracking-[0.2em] uppercase">Kodun 0'dan 6'ya Evrimi</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 className="text-5xl md:text-8xl font-mono font-black text-white mb-6 tracking-tight leading-none animate-in fade-in zoom-in-95 duration-1000">
|
||||||
|
GELECEĞİ <br />
|
||||||
|
<span className="relative inline-block">
|
||||||
|
<span className="absolute -inset-1 bg-zsl-primary/20 blur-lg filter"></span>
|
||||||
|
<span className="relative text-transparent bg-clip-text bg-linear-to-r from-zsl-primary via-white to-zsl-accent">KODLAYAN</span>
|
||||||
|
</span> <br />
|
||||||
|
LABORATUVAR
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p className="text-xl text-zsl-muted max-w-2xl mx-auto mb-12 font-light animate-in fade-in slide-in-from-bottom-4 duration-1000 delay-200">
|
||||||
|
ZeroSixLab: Dijital dünyaya Ankara gözüyle bakıyoruz. Karmaşık sorunlara, mantık ve yaratıcılığı birleştiren akıllı çözümler.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="flex flex-col sm:flex-row gap-6 justify-center items-center animate-in fade-in slide-in-from-bottom-8 duration-1000 delay-300">
|
||||||
|
<button
|
||||||
|
onClick={() => handleNavClick(NavPage.PROJECTS)}
|
||||||
|
className="px-8 py-4 bg-zsl-primary text-black font-mono font-bold text-lg rounded hover:bg-white hover:shadow-[0_0_30px_rgba(255,255,255,0.4)] transition-all duration-300 transform hover:-translate-y-1 w-full sm:w-auto"
|
||||||
|
>
|
||||||
|
PROJELERİ GÖR
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => handleNavClick(NavPage.CONTACT)}
|
||||||
|
className="px-8 py-4 bg-transparent border border-zsl-accent text-zsl-accent font-mono font-bold text-lg rounded hover:bg-zsl-accent/10 hover:shadow-[0_0_20px_rgba(255,170,0,0.3)] transition-all duration-300 transform hover:-translate-y-1 w-full sm:w-auto"
|
||||||
|
>
|
||||||
|
TEKLİF AL
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<TechStackMarquee />
|
||||||
|
|
||||||
|
{/* Stats Section */}
|
||||||
|
<ScrollAnimation animation="fade-up">
|
||||||
|
<div className="max-w-7xl mx-auto px-4 mb-20">
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
|
||||||
|
<AnimatedCounter
|
||||||
|
end={50}
|
||||||
|
suffix="+"
|
||||||
|
title="Tamamlanan Proje"
|
||||||
|
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="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z" /></svg>}
|
||||||
|
/>
|
||||||
|
<AnimatedCounter
|
||||||
|
end={30}
|
||||||
|
suffix="+"
|
||||||
|
title="Mutlu Müşteri"
|
||||||
|
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
|
||||||
|
end={3}
|
||||||
|
suffix="+"
|
||||||
|
title="Yıllık Deneyim"
|
||||||
|
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="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>}
|
||||||
|
/>
|
||||||
|
<AnimatedCounter
|
||||||
|
end={99}
|
||||||
|
suffix="%"
|
||||||
|
title="Müşteri Memnuniyeti"
|
||||||
|
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>
|
||||||
|
</ScrollAnimation>
|
||||||
|
|
||||||
|
{/* Services Grid Summary */}
|
||||||
|
<ScrollAnimation animation="fade-up" delay={100}>
|
||||||
|
<div className="max-w-7xl mx-auto grid grid-cols-1 md:grid-cols-3 gap-6 mt-10">
|
||||||
|
<FeatureCard
|
||||||
|
title="Bilişsel Sistemler"
|
||||||
|
description="Yüksek hız ve düşük gecikme süresiyle karmaşık akıl yürütme görevlerini işlemek için en yeni LLM'ler."
|
||||||
|
accentColor="primary"
|
||||||
|
icon={(
|
||||||
|
<svg className="w-10 h-10" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FeatureCard
|
||||||
|
title="Sınırları Kaldıran Çözümler"
|
||||||
|
description="Fikirden dijitale kusursuz dönüşüm. Web, Mobil ve Bulut tabanlı ölçeklenebilir mimariler."
|
||||||
|
accentColor="accent"
|
||||||
|
icon={(
|
||||||
|
<svg className="w-10 h-10" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M19.428 15.428a2 2 0 00-1.022-.547l-2.384-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FeatureCard
|
||||||
|
title="Güvenli Altyapı"
|
||||||
|
description="Kurumsal düzeyde şifreleme ve güvenlik protokolleri ile verileriniz nöral ağımızda güvende."
|
||||||
|
accentColor="primary"
|
||||||
|
icon={(
|
||||||
|
<svg className="w-10 h-10" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ScrollAnimation>
|
||||||
|
|
||||||
|
<div className="text-center mt-12">
|
||||||
|
<button onClick={() => handleNavClick(NavPage.SERVICES)} className="text-zsl-primary hover:text-white font-mono text-sm border-b border-zsl-primary hover:border-white transition-all pb-1 uppercase tracking-wider">Tüm Yetenekleri İncele →</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Testimonials Section */}
|
||||||
|
<ScrollAnimation animation="fade-up" delay={200}>
|
||||||
|
<div className="max-w-7xl mx-auto px-4 mt-32">
|
||||||
|
<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>
|
||||||
|
<h2 className="text-3xl md:text-4xl font-mono font-bold text-white">Müşterilerimiz Ne Diyor?</h2>
|
||||||
|
</div>
|
||||||
|
<TestimonialSlider testimonials={testimonials} />
|
||||||
|
</div>
|
||||||
|
</ScrollAnimation>
|
||||||
|
|
||||||
|
{/* Partners Section */}
|
||||||
|
<ScrollAnimation animation="fade-up" delay={300}>
|
||||||
|
<div className="max-w-7xl mx-auto px-4 mt-32">
|
||||||
|
<div className="text-center mb-8">
|
||||||
|
<span className="text-xs font-mono text-zsl-muted uppercase tracking-widest">Güvendikleri markalar</span>
|
||||||
|
</div>
|
||||||
|
<PartnerLogos partners={partners} />
|
||||||
|
</div>
|
||||||
|
</ScrollAnimation>
|
||||||
|
|
||||||
|
{/* FAQ Section */}
|
||||||
|
<ScrollAnimation animation="fade-up" delay={400}>
|
||||||
|
<div className="max-w-7xl mx-auto px-4 mt-32">
|
||||||
|
<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">SSS</span>
|
||||||
|
<h2 className="text-3xl md:text-4xl font-mono font-bold text-white mb-4">Sıkça Sorulan Sorular</h2>
|
||||||
|
<p className="text-zsl-muted max-w-2xl mx-auto">Merak ettiklerinizi yanıtladık. Daha fazla sorunuz varsa bizimle iletişime geçmekten çekinmeyin.</p>
|
||||||
|
</div>
|
||||||
|
<FAQAccordion items={faqItems} />
|
||||||
|
</div>
|
||||||
|
</ScrollAnimation>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-zsl-bg text-zsl-text font-sans selection:bg-zsl-primary selection:text-black">
|
||||||
|
{/* Loading Screen */}
|
||||||
|
{isLoading && <LoadingScreen />}
|
||||||
|
|
||||||
|
{/* Custom Cursor */}
|
||||||
|
<CustomCursor />
|
||||||
|
|
||||||
|
{/* Particle Background */}
|
||||||
|
<ParticleBackground />
|
||||||
|
|
||||||
|
{/* Navigation Bar */}
|
||||||
|
<nav className={`fixed top-0 left-0 w-full z-50 transition-all duration-300 ${scrolled ? 'bg-zsl-bg/90 backdrop-blur-md shadow-lg border-b border-white/5' : 'bg-transparent'}`}>
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div className="flex items-center justify-between h-24">
|
||||||
|
<div
|
||||||
|
className="cursor-pointer transition-transform hover:scale-105 z-50"
|
||||||
|
onClick={() => handleNavClick(NavPage.HOME)}
|
||||||
|
>
|
||||||
|
<Logo size="md" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Desktop Menu */}
|
||||||
|
<div className="hidden md:flex items-center space-x-1 ml-10">
|
||||||
|
{[
|
||||||
|
{ page: NavPage.HOME, label: 'ANA SAYFA' },
|
||||||
|
{ page: NavPage.SERVICES, label: 'ÇÖZÜMLER' },
|
||||||
|
{ page: NavPage.PROJECTS, label: 'LAB SONUÇLARI' },
|
||||||
|
{ page: NavPage.BLOG, label: 'LAB NOTLARI' },
|
||||||
|
{ page: NavPage.ABOUT, label: 'HİKAYE' },
|
||||||
|
{ page: NavPage.LAB, label: 'AI LAB' },
|
||||||
|
{ page: NavPage.CONTACT, label: 'BAĞLANTI' }
|
||||||
|
].map((item) => (
|
||||||
|
<button
|
||||||
|
key={item.page}
|
||||||
|
onClick={() => handleNavClick(item.page)}
|
||||||
|
className={`px-4 py-2 rounded-full text-xs font-mono font-bold tracking-widest transition-all ${
|
||||||
|
currentPage === item.page
|
||||||
|
? 'text-white bg-white/10 shadow-[0_0_10px_rgba(255,255,255,0.1)]'
|
||||||
|
: 'text-slate-400 hover:text-white hover:bg-white/5'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Mobile Menu Button */}
|
||||||
|
<div className="md:hidden z-50">
|
||||||
|
<button onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)} className="text-white p-2">
|
||||||
|
{isMobileMenuOpen ? (
|
||||||
|
<svg className="w-8 h-8 text-zsl-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" /></svg>
|
||||||
|
) : (
|
||||||
|
<svg className="w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" /></svg>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Mobile Menu Overlay */}
|
||||||
|
{isMobileMenuOpen && (
|
||||||
|
<div className="md:hidden fixed inset-0 bg-zsl-bg/95 backdrop-blur-xl z-40 flex flex-col items-center justify-center space-y-8 animate-in slide-in-from-top-10">
|
||||||
|
{[
|
||||||
|
{ page: NavPage.HOME, label: 'ANA SAYFA' },
|
||||||
|
{ page: NavPage.SERVICES, label: 'ÇÖZÜMLER' },
|
||||||
|
{ page: NavPage.PROJECTS, label: 'LAB SONUÇLARI' },
|
||||||
|
{ page: NavPage.BLOG, label: 'LAB NOTLARI' },
|
||||||
|
{ page: NavPage.ABOUT, label: 'HİKAYE' },
|
||||||
|
{ page: NavPage.LAB, label: 'AI LAB' },
|
||||||
|
{ page: NavPage.CONTACT, label: 'BAĞLANTI' }
|
||||||
|
].map((item) => (
|
||||||
|
<button
|
||||||
|
key={item.page}
|
||||||
|
onClick={() => handleNavClick(item.page)}
|
||||||
|
className={`text-xl font-mono font-bold tracking-widest ${
|
||||||
|
currentPage === item.page
|
||||||
|
? 'text-zsl-primary border border-zsl-primary px-6 py-2 rounded shadow-[0_0_15px_rgba(0,212,255,0.3)]'
|
||||||
|
: 'text-white hover:text-zsl-primary'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{/* Main Content */}
|
||||||
|
<main className="relative pt-0 z-10">
|
||||||
|
{renderContent()}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<footer className="border-t border-white/5 bg-[#050B14] py-12 mt-20 relative overflow-hidden z-10">
|
||||||
|
<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="flex flex-col items-center md:items-start gap-2">
|
||||||
|
<Logo size="sm" />
|
||||||
|
<p className="font-mono text-slate-500 text-xs mt-2 text-center md:text-left">
|
||||||
|
© 2024 ZeroSixLab. Tüm Hakları Saklıdır.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex gap-6">
|
||||||
|
{['Twitter', 'LinkedIn', 'GitHub'].map((social) => (
|
||||||
|
<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>
|
||||||
|
))}
|
||||||
|
</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>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
{/* Scroll To Top Button */}
|
||||||
|
<ScrollToTop />
|
||||||
|
|
||||||
|
{/* Cookie Banner */}
|
||||||
|
<CookieBanner />
|
||||||
|
|
||||||
|
{/* Project Modal */}
|
||||||
|
<ProjectModal
|
||||||
|
project={selectedProject}
|
||||||
|
isOpen={isProjectModalOpen}
|
||||||
|
onClose={() => setIsProjectModalOpen(false)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
98
my-app/src/components/AnimatedCounter.tsx
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
interface AnimatedCounterProps {
|
||||||
|
end: number;
|
||||||
|
duration?: number;
|
||||||
|
suffix?: string;
|
||||||
|
prefix?: string;
|
||||||
|
title: string;
|
||||||
|
icon: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AnimatedCounter: React.FC<AnimatedCounterProps> = ({
|
||||||
|
end,
|
||||||
|
duration = 2000,
|
||||||
|
suffix = '',
|
||||||
|
prefix = '',
|
||||||
|
title,
|
||||||
|
icon
|
||||||
|
}) => {
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
([entry]) => {
|
||||||
|
if (entry.isIntersecting && !isVisible) {
|
||||||
|
setIsVisible(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ threshold: 0.3 }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ref.current) {
|
||||||
|
observer.observe(ref.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, [isVisible]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isVisible) return;
|
||||||
|
|
||||||
|
let startTime: number;
|
||||||
|
let animationFrame: number;
|
||||||
|
|
||||||
|
const animate = (timestamp: number) => {
|
||||||
|
if (!startTime) startTime = timestamp;
|
||||||
|
const progress = Math.min((timestamp - startTime) / duration, 1);
|
||||||
|
|
||||||
|
// Easing function for smooth animation
|
||||||
|
const easeOutQuart = 1 - Math.pow(1 - progress, 4);
|
||||||
|
|
||||||
|
setCount(Math.floor(easeOutQuart * end));
|
||||||
|
|
||||||
|
if (progress < 1) {
|
||||||
|
animationFrame = requestAnimationFrame(animate);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
animationFrame = requestAnimationFrame(animate);
|
||||||
|
|
||||||
|
return () => cancelAnimationFrame(animationFrame);
|
||||||
|
}, [isVisible, end, duration]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
className="relative group p-6 bg-zsl-card/50 backdrop-blur-sm border border-zsl-primary/20 rounded-xl hover:border-zsl-primary/50 transition-all duration-300"
|
||||||
|
>
|
||||||
|
{/* Background Glow */}
|
||||||
|
<div className="absolute inset-0 bg-zsl-primary/5 rounded-xl opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
|
||||||
|
|
||||||
|
{/* Icon */}
|
||||||
|
<div className="text-zsl-primary text-3xl mb-4 group-hover:scale-110 transition-transform duration-300">
|
||||||
|
{icon}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Counter */}
|
||||||
|
<div className="font-mono text-4xl md:text-5xl font-bold text-white mb-2">
|
||||||
|
<span className="text-zsl-primary">{prefix}</span>
|
||||||
|
{count.toLocaleString()}
|
||||||
|
<span className="text-zsl-accent">{suffix}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Title */}
|
||||||
|
<div className="text-zsl-muted text-sm uppercase tracking-wider">
|
||||||
|
{title}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Decorative Corner */}
|
||||||
|
<div className="absolute top-0 right-0 w-8 h-8 border-t-2 border-r-2 border-zsl-primary/30 rounded-tr-xl" />
|
||||||
|
<div className="absolute bottom-0 left-0 w-8 h-8 border-b-2 border-l-2 border-zsl-primary/30 rounded-bl-xl" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
191
my-app/src/components/ChatInterface.tsx
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
|
import { Message } from '@/types';
|
||||||
|
import { streamChatResponse } from '@/services/geminiService';
|
||||||
|
|
||||||
|
const ChatInterface: React.FC = () => {
|
||||||
|
const [input, setInput] = useState('');
|
||||||
|
const [messages, setMessages] = useState<Message[]>([
|
||||||
|
{
|
||||||
|
id: 'welcome',
|
||||||
|
role: 'model',
|
||||||
|
text: "Sistem aktif. ZeroSixLab AI arayüzüne hoş geldiniz. Araştırmanız veya projeniz için nasıl yardımcı olabilirim?",
|
||||||
|
timestamp: new Date(),
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [isInitialLoad, setIsInitialLoad] = useState(true);
|
||||||
|
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||||||
|
const messagesContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
const scrollToBottom = () => {
|
||||||
|
// Only scroll inside the messages container, not the whole page
|
||||||
|
if (messagesContainerRef.current) {
|
||||||
|
messagesContainerRef.current.scrollTop = messagesContainerRef.current.scrollHeight;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Skip auto-scroll on initial load
|
||||||
|
if (isInitialLoad) {
|
||||||
|
setIsInitialLoad(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scrollToBottom();
|
||||||
|
}, [messages, isInitialLoad]);
|
||||||
|
|
||||||
|
// Focus input on load (without scrolling page)
|
||||||
|
useEffect(() => {
|
||||||
|
inputRef.current?.focus({ preventScroll: true });
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleSend = async () => {
|
||||||
|
if (!input.trim() || isLoading) return;
|
||||||
|
|
||||||
|
const userMsg: Message = {
|
||||||
|
id: Date.now().toString(),
|
||||||
|
role: 'user',
|
||||||
|
text: input,
|
||||||
|
timestamp: new Date(),
|
||||||
|
};
|
||||||
|
|
||||||
|
setMessages(prev => [...prev, userMsg]);
|
||||||
|
setInput('');
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
// Prepare history for API
|
||||||
|
const history = messages.map(m => ({
|
||||||
|
role: m.role,
|
||||||
|
parts: [{ text: m.text }]
|
||||||
|
}));
|
||||||
|
|
||||||
|
try {
|
||||||
|
const stream = await streamChatResponse(userMsg.text, history);
|
||||||
|
|
||||||
|
const modelMsgId = (Date.now() + 1).toString();
|
||||||
|
const modelMsg: Message = {
|
||||||
|
id: modelMsgId,
|
||||||
|
role: 'model',
|
||||||
|
text: '',
|
||||||
|
timestamp: new Date(),
|
||||||
|
};
|
||||||
|
|
||||||
|
setMessages(prev => [...prev, modelMsg]);
|
||||||
|
|
||||||
|
let fullText = '';
|
||||||
|
for await (const chunk of stream) {
|
||||||
|
fullText += chunk;
|
||||||
|
setMessages(prev =>
|
||||||
|
prev.map(msg => msg.id === modelMsgId ? { ...msg, text: fullText } : msg)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
setMessages(prev => [...prev, {
|
||||||
|
id: Date.now().toString(),
|
||||||
|
role: 'model',
|
||||||
|
text: "Hata: Nöral bağlantı kararsız. Lütfen API anahtarını kontrol edin.",
|
||||||
|
timestamp: new Date(),
|
||||||
|
isError: true
|
||||||
|
}]);
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col h-162.5 w-full max-w-5xl mx-auto glass-panel rounded-xl shadow-2xl overflow-hidden relative border border-zsl-primary/20 group">
|
||||||
|
{/* Decorative Corner Lines */}
|
||||||
|
<div className="absolute top-0 left-0 w-8 h-8 border-t-2 border-l-2 border-zsl-primary/50 rounded-tl-xl z-20"></div>
|
||||||
|
<div className="absolute top-0 right-0 w-8 h-8 border-t-2 border-r-2 border-zsl-primary/50 rounded-tr-xl z-20"></div>
|
||||||
|
<div className="absolute bottom-0 left-0 w-8 h-8 border-b-2 border-l-2 border-zsl-primary/50 rounded-bl-xl z-20"></div>
|
||||||
|
<div className="absolute bottom-0 right-0 w-8 h-8 border-b-2 border-r-2 border-zsl-primary/50 rounded-br-xl z-20"></div>
|
||||||
|
|
||||||
|
{/* HUD Header */}
|
||||||
|
<div className="bg-black/40 p-3 border-b border-zsl-primary/20 flex justify-between items-center backdrop-blur-md z-10">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="relative">
|
||||||
|
<div className="w-2.5 h-2.5 bg-zsl-accent rounded-full animate-pulse shadow-[0_0_10px_#FFAA00]"></div>
|
||||||
|
<div className="absolute inset-0 bg-zsl-accent rounded-full animate-ping opacity-20"></div>
|
||||||
|
</div>
|
||||||
|
<span className="font-mono text-xs text-zsl-primary tracking-widest font-bold">CANLI_BAĞLANTI // GEMINI-2.5-FLASH</span>
|
||||||
|
</div>
|
||||||
|
<div className="font-mono text-[10px] text-zsl-muted flex gap-4 uppercase tracking-wider">
|
||||||
|
<span className="hidden sm:inline">MEM: <span className="text-zsl-primary">32GB</span></span>
|
||||||
|
<span className="hidden sm:inline">NET: <span className="text-green-400">SECURE</span></span>
|
||||||
|
<span>LATENCY: <span className="text-zsl-primary">12ms</span></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Background Effect inside Chat */}
|
||||||
|
<div className="absolute inset-0 bg-[linear-gradient(rgba(10,25,47,0.8)_2px,transparent_2px)] bg-size-[100%_4px] pointer-events-none opacity-20"></div>
|
||||||
|
|
||||||
|
{/* Messages Area */}
|
||||||
|
<div ref={messagesContainerRef} className="flex-1 overflow-y-auto p-6 space-y-6 scrollbar-thin scrollbar-thumb-zsl-card relative z-10">
|
||||||
|
{messages.map((msg) => (
|
||||||
|
<div key={msg.id} className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`}>
|
||||||
|
<div className={`max-w-[85%] rounded-xl p-5 relative transition-all duration-300 ${
|
||||||
|
msg.role === 'user'
|
||||||
|
? 'bg-zsl-primary/10 border border-zsl-primary/30 text-white rounded-tr-none shadow-[0_0_15px_rgba(0,212,255,0.05)]'
|
||||||
|
: 'bg-[#0f1d35] border border-slate-700/50 text-zsl-text rounded-tl-none shadow-lg'
|
||||||
|
} ${msg.isError ? 'border-red-500/50 text-red-200 bg-red-900/10' : ''}`}>
|
||||||
|
|
||||||
|
<div className="font-mono text-[10px] uppercase opacity-60 mb-2 flex justify-between gap-4 border-b border-white/5 pb-1 select-none">
|
||||||
|
<span className={`font-bold ${msg.role === 'user' ? 'text-zsl-primary' : 'text-zsl-accent'}`}>
|
||||||
|
{msg.role === 'user' ? '>> OPERATOR' : '>> ZERO_AI'}
|
||||||
|
</span>
|
||||||
|
<span>{msg.timestamp.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="whitespace-pre-wrap leading-relaxed text-sm md:text-base font-light tracking-wide">
|
||||||
|
{msg.text}
|
||||||
|
{msg.role === 'model' && msg.id === messages[messages.length - 1].id && isLoading && (
|
||||||
|
<span className="inline-block w-2 h-4 bg-zsl-accent ml-1 animate-pulse align-middle"></span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Decorative side accent for model */}
|
||||||
|
{msg.role === 'model' && (
|
||||||
|
<div className="absolute left-0 top-6 w-0.5 h-8 bg-zsl-accent shadow-[0_0_10px_#FFAA00]"></div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{/* Loading Indicator */}
|
||||||
|
{isLoading && messages[messages.length - 1].role === 'user' && (
|
||||||
|
<div className="flex justify-start animate-in fade-in duration-300">
|
||||||
|
<div className="bg-[#0f1d35] p-3 rounded-lg rounded-tl-none border border-slate-700/50 flex items-center gap-2">
|
||||||
|
<span className="font-mono text-xs text-zsl-accent animate-pulse">PROCESSING...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div ref={messagesEndRef} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Input Area */}
|
||||||
|
<div className="p-4 bg-black/40 border-t border-zsl-primary/20 backdrop-blur relative z-10">
|
||||||
|
<div className="relative flex items-center gap-3">
|
||||||
|
<div className="absolute left-4 top-1/2 -translate-y-1/2 text-zsl-primary font-mono text-lg animate-pulse">{'>'}</div>
|
||||||
|
<input
|
||||||
|
ref={inputRef}
|
||||||
|
type="text"
|
||||||
|
value={input}
|
||||||
|
onChange={(e) => setInput(e.target.value)}
|
||||||
|
onKeyDown={(e) => e.key === 'Enter' && handleSend()}
|
||||||
|
placeholder="Komut girişi yapın..."
|
||||||
|
className="flex-1 bg-zsl-bg/50 border border-slate-700 focus:border-zsl-primary text-white pl-8 pr-5 py-4 rounded-lg font-mono text-sm outline-none transition-all placeholder-slate-600 focus:shadow-[0_0_15px_rgba(0,212,255,0.1)] focus:bg-zsl-bg/80"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onClick={handleSend}
|
||||||
|
disabled={isLoading || !input.trim()}
|
||||||
|
className="bg-zsl-primary hover:bg-white text-black px-6 py-4 rounded-lg font-mono text-sm font-bold uppercase transition-all hover:shadow-[0_0_20px_rgba(0,212,255,0.4)] disabled:opacity-50 disabled:cursor-not-allowed group relative overflow-hidden active:scale-95"
|
||||||
|
>
|
||||||
|
<span className="relative z-10">GÖNDER</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ChatInterface;
|
||||||
89
my-app/src/components/CookieBanner.tsx
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
interface CookieBannerProps {
|
||||||
|
onAccept?: () => void;
|
||||||
|
onDecline?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CookieBanner: React.FC<CookieBannerProps> = ({ onAccept, onDecline }) => {
|
||||||
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Check if user has already made a choice
|
||||||
|
const consent = localStorage.getItem('cookie-consent');
|
||||||
|
if (!consent) {
|
||||||
|
// Small delay for better UX
|
||||||
|
setTimeout(() => setIsVisible(true), 1500);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleAccept = () => {
|
||||||
|
localStorage.setItem('cookie-consent', 'accepted');
|
||||||
|
setIsVisible(false);
|
||||||
|
onAccept?.();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDecline = () => {
|
||||||
|
localStorage.setItem('cookie-consent', 'declined');
|
||||||
|
setIsVisible(false);
|
||||||
|
onDecline?.();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!isVisible) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="fixed bottom-0 left-0 right-0 z-50 p-4 md:p-6">
|
||||||
|
<div className="max-w-4xl mx-auto bg-zsl-card/95 backdrop-blur-md border border-zsl-primary/20 rounded-2xl p-6 shadow-2xl shadow-black/50">
|
||||||
|
<div className="flex flex-col md:flex-row items-start md:items-center gap-4">
|
||||||
|
{/* Icon */}
|
||||||
|
<div className="w-12 h-12 rounded-xl bg-zsl-primary/10 flex items-center justify-center shrink-0">
|
||||||
|
<svg className="w-6 h-6 text-zsl-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Text */}
|
||||||
|
<div className="flex-1">
|
||||||
|
<h3 className="font-semibold text-white mb-1">🍪 Çerez Kullanımı & KVKK</h3>
|
||||||
|
<p className="text-sm text-zsl-muted leading-relaxed">
|
||||||
|
Web sitemizde deneyiminizi iyileştirmek için çerezler kullanıyoruz.
|
||||||
|
Kişisel verileriniz 6698 sayılı KVKK kapsamında korunmaktadır.
|
||||||
|
Devam ederek{' '}
|
||||||
|
<a href="#" className="text-zsl-primary hover:underline">Gizlilik Politikamızı</a>
|
||||||
|
{' '}kabul etmiş olursunuz.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Buttons */}
|
||||||
|
<div className="flex gap-3 shrink-0 w-full md:w-auto">
|
||||||
|
<button
|
||||||
|
onClick={handleDecline}
|
||||||
|
className="flex-1 md:flex-none px-5 py-2.5 text-sm font-medium text-zsl-muted border border-zsl-primary/20 rounded-lg hover:border-zsl-primary/40 hover:text-white transition-all duration-300"
|
||||||
|
>
|
||||||
|
Reddet
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handleAccept}
|
||||||
|
className="flex-1 md:flex-none px-5 py-2.5 text-sm font-medium bg-zsl-primary text-zsl-bg rounded-lg hover:bg-zsl-primary/90 transition-all duration-300"
|
||||||
|
>
|
||||||
|
Kabul Et
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Close button */}
|
||||||
|
<button
|
||||||
|
onClick={handleDecline}
|
||||||
|
className="absolute top-3 right-3 w-8 h-8 rounded-full flex items-center justify-center text-zsl-muted hover:text-white hover:bg-zsl-primary/10 transition-all duration-300"
|
||||||
|
aria-label="Kapat"
|
||||||
|
>
|
||||||
|
<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>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
111
my-app/src/components/CustomCursor.tsx
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
export const CustomCursor: React.FC = () => {
|
||||||
|
const [position, setPosition] = useState({ x: 0, y: 0 });
|
||||||
|
const [isPointer, setIsPointer] = useState(false);
|
||||||
|
const [isClicking, setIsClicking] = useState(false);
|
||||||
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Check if device supports hover (not touch)
|
||||||
|
const hasHover = window.matchMedia('(hover: hover)').matches;
|
||||||
|
if (!hasHover) return;
|
||||||
|
|
||||||
|
const handleMouseMove = (e: MouseEvent) => {
|
||||||
|
setPosition({ x: e.clientX, y: e.clientY });
|
||||||
|
setIsVisible(true);
|
||||||
|
|
||||||
|
const target = e.target as HTMLElement;
|
||||||
|
const isClickable = !!(
|
||||||
|
target.tagName === 'BUTTON' ||
|
||||||
|
target.tagName === 'A' ||
|
||||||
|
target.closest('button') ||
|
||||||
|
target.closest('a') ||
|
||||||
|
target.style.cursor === 'pointer' ||
|
||||||
|
window.getComputedStyle(target).cursor === 'pointer'
|
||||||
|
);
|
||||||
|
|
||||||
|
setIsPointer(isClickable);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseDown = () => setIsClicking(true);
|
||||||
|
const handleMouseUp = () => setIsClicking(false);
|
||||||
|
const handleMouseLeave = () => setIsVisible(false);
|
||||||
|
const handleMouseEnter = () => setIsVisible(true);
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', handleMouseMove);
|
||||||
|
document.addEventListener('mousedown', handleMouseDown);
|
||||||
|
document.addEventListener('mouseup', handleMouseUp);
|
||||||
|
document.documentElement.addEventListener('mouseleave', handleMouseLeave);
|
||||||
|
document.documentElement.addEventListener('mouseenter', handleMouseEnter);
|
||||||
|
|
||||||
|
// Hide default cursor
|
||||||
|
document.body.style.cursor = 'none';
|
||||||
|
document.querySelectorAll('a, button').forEach(el => {
|
||||||
|
(el as HTMLElement).style.cursor = 'none';
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('mousemove', handleMouseMove);
|
||||||
|
document.removeEventListener('mousedown', handleMouseDown);
|
||||||
|
document.removeEventListener('mouseup', handleMouseUp);
|
||||||
|
document.documentElement.removeEventListener('mouseleave', handleMouseLeave);
|
||||||
|
document.documentElement.removeEventListener('mouseenter', handleMouseEnter);
|
||||||
|
document.body.style.cursor = 'auto';
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!isVisible) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Main cursor dot */}
|
||||||
|
<div
|
||||||
|
className="fixed pointer-events-none z-9999 mix-blend-difference"
|
||||||
|
style={{
|
||||||
|
left: position.x,
|
||||||
|
top: position.y,
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={`
|
||||||
|
rounded-full bg-zsl-primary transition-all duration-150 ease-out
|
||||||
|
${isClicking ? 'w-2 h-2' : isPointer ? 'w-4 h-4' : 'w-3 h-3'}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Outer ring */}
|
||||||
|
<div
|
||||||
|
className="fixed pointer-events-none z-9998 transition-all duration-300 ease-out"
|
||||||
|
style={{
|
||||||
|
left: position.x,
|
||||||
|
top: position.y,
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={`
|
||||||
|
rounded-full border-2 border-zsl-primary/50 transition-all duration-200 ease-out
|
||||||
|
${isClicking ? 'w-6 h-6 border-zsl-accent' : isPointer ? 'w-10 h-10 border-zsl-accent' : 'w-8 h-8'}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
</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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
67
my-app/src/components/FAQAccordion.tsx
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
interface FAQItem {
|
||||||
|
question: string;
|
||||||
|
answer: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FAQAccordionProps {
|
||||||
|
items: FAQItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FAQAccordion: React.FC<FAQAccordionProps> = ({ items }) => {
|
||||||
|
const [openIndex, setOpenIndex] = useState<number | null>(0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-4 max-w-3xl mx-auto">
|
||||||
|
{items.map((item, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className={`
|
||||||
|
border rounded-xl overflow-hidden transition-all duration-300
|
||||||
|
${openIndex === index
|
||||||
|
? 'border-zsl-primary/50 bg-zsl-card/50'
|
||||||
|
: 'border-zsl-primary/10 bg-zsl-card/30 hover:border-zsl-primary/30'
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{/* Question */}
|
||||||
|
<button
|
||||||
|
onClick={() => setOpenIndex(openIndex === index ? null : index)}
|
||||||
|
className="w-full px-6 py-5 flex items-center justify-between text-left"
|
||||||
|
>
|
||||||
|
<span className="font-medium text-white pr-4">{item.question}</span>
|
||||||
|
<div className={`
|
||||||
|
w-8 h-8 rounded-full border border-zsl-primary/30 flex items-center justify-center
|
||||||
|
transition-all duration-300 shrink-0
|
||||||
|
${openIndex === index ? 'bg-zsl-primary rotate-180' : ''}
|
||||||
|
`}>
|
||||||
|
<svg
|
||||||
|
className={`w-4 h-4 transition-colors duration-300 ${openIndex === index ? 'text-zsl-bg' : 'text-zsl-primary'}`}
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Answer */}
|
||||||
|
<div className={`
|
||||||
|
grid transition-all duration-300 ease-in-out
|
||||||
|
${openIndex === index ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]'}
|
||||||
|
`}>
|
||||||
|
<div className="overflow-hidden">
|
||||||
|
<div className="px-6 pb-5 text-zsl-muted leading-relaxed border-t border-zsl-primary/10 pt-4">
|
||||||
|
{item.answer}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
44
my-app/src/components/FeatureCard.tsx
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { FeatureCardProps } from '@/types';
|
||||||
|
|
||||||
|
export const FeatureCard: React.FC<FeatureCardProps> = ({ title, description, icon, accentColor }) => {
|
||||||
|
const accentClass = accentColor === 'primary'
|
||||||
|
? 'border-zsl-primary/20 text-zsl-primary group-hover:border-zsl-primary/50'
|
||||||
|
: 'border-zsl-accent/20 text-zsl-accent group-hover:border-zsl-accent/50';
|
||||||
|
|
||||||
|
const bgGradient = accentColor === 'primary'
|
||||||
|
? 'from-zsl-card to-zsl-bg group-hover:shadow-[0_0_30px_rgba(0,212,255,0.15)]'
|
||||||
|
: 'from-zsl-card to-zsl-bg group-hover:shadow-[0_0_30px_rgba(255,170,0,0.15)]';
|
||||||
|
|
||||||
|
const iconBg = accentColor === 'primary' ? 'bg-zsl-primary/10' : 'bg-zsl-accent/10';
|
||||||
|
const iconColor = accentColor === 'primary' ? 'text-zsl-primary' : 'text-zsl-accent';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`group p-6 rounded-xl border ${accentClass} bg-linear-to-br ${bgGradient} transition-all duration-300 transform hover:-translate-y-2 relative overflow-hidden h-full backdrop-blur-sm`}>
|
||||||
|
{/* Tech Circuit Pattern Background (Visible on Hover) */}
|
||||||
|
<div className="absolute inset-0 opacity-0 group-hover:opacity-10 transition-opacity duration-500 pointer-events-none">
|
||||||
|
<svg className="w-full h-full" width="100%" height="100%">
|
||||||
|
<pattern id={`circuit-${title.replace(/\s/g, '')}`} x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
|
||||||
|
<path d="M10 0v20M0 10h20" stroke="currentColor" strokeWidth="0.5" fill="none" />
|
||||||
|
</pattern>
|
||||||
|
<rect width="100%" height="100%" fill={`url(#circuit-${title.replace(/\s/g, '')})`} />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="absolute top-0 right-0 p-3 opacity-20 group-hover:opacity-40 transition-opacity rotate-12 group-hover:rotate-0 duration-500">
|
||||||
|
<svg width="60" height="60" viewBox="0 0 100 100" fill="none" className={accentColor === 'primary' ? 'stroke-zsl-primary' : 'stroke-zsl-accent'}>
|
||||||
|
<circle cx="50" cy="50" r="40" strokeWidth="1" strokeDasharray="4 4" className="animate-spin-slow" />
|
||||||
|
<path d="M50 10 L50 90 M10 50 L90 50" strokeWidth="0.5" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-6 relative z-10">
|
||||||
|
<div className={`p-3 rounded-lg inline-flex items-center justify-center ${iconBg} ${iconColor} group-hover:scale-110 transition-all shadow-lg`}>
|
||||||
|
{icon}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-xl font-mono font-bold text-white mb-3 relative z-10 group-hover:translate-x-1 transition-transform">{title}</h3>
|
||||||
|
<p className="text-zsl-muted text-sm leading-relaxed relative z-10 group-hover:text-zsl-text transition-colors">{description}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
80
my-app/src/components/LoadingScreen.tsx
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { Logo } from './Logo';
|
||||||
|
|
||||||
|
export const LoadingScreen: React.FC = () => {
|
||||||
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const [progress, setProgress] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
setProgress(prev => {
|
||||||
|
if (prev >= 100) {
|
||||||
|
clearInterval(interval);
|
||||||
|
setTimeout(() => setIsLoading(false), 300);
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
return prev + Math.random() * 15;
|
||||||
|
});
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!isLoading) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`fixed inset-0 z-100 bg-zsl-bg flex flex-col items-center justify-center transition-opacity duration-500 ${progress >= 100 ? 'opacity-0' : 'opacity-100'}`}>
|
||||||
|
{/* Cyber Grid Background */}
|
||||||
|
<div className="absolute inset-0 cyber-grid opacity-20"></div>
|
||||||
|
|
||||||
|
{/* Floating Particles */}
|
||||||
|
<div className="absolute inset-0 overflow-hidden">
|
||||||
|
{[...Array(20)].map((_, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className="absolute w-1 h-1 bg-zsl-primary/50 rounded-full animate-pulse"
|
||||||
|
style={{
|
||||||
|
left: `${Math.random() * 100}%`,
|
||||||
|
top: `${Math.random() * 100}%`,
|
||||||
|
animationDelay: `${Math.random() * 2}s`,
|
||||||
|
animationDuration: `${2 + Math.random() * 3}s`
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Logo with Glow Animation */}
|
||||||
|
<div className="relative mb-8 animate-pulse">
|
||||||
|
<div className="absolute inset-0 bg-zsl-primary/20 rounded-full blur-3xl scale-150"></div>
|
||||||
|
<Logo size="lg" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Loading Text */}
|
||||||
|
<div className="font-mono text-zsl-primary text-sm tracking-widest mb-6 uppercase">
|
||||||
|
Sistem Başlatılıyor...
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Progress Bar */}
|
||||||
|
<div className="w-64 h-1 bg-zsl-card rounded-full overflow-hidden">
|
||||||
|
<div
|
||||||
|
className="h-full bg-linear-to-r from-zsl-primary to-zsl-accent transition-all duration-200 ease-out"
|
||||||
|
style={{ width: `${Math.min(progress, 100)}%` }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Progress Percentage */}
|
||||||
|
<div className="font-mono text-xs text-zsl-muted mt-3">
|
||||||
|
{Math.min(Math.round(progress), 100)}%
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Terminal-style Messages */}
|
||||||
|
<div className="absolute bottom-8 left-8 font-mono text-[10px] text-zsl-muted/50 hidden md:block">
|
||||||
|
<div className="animate-pulse">> Modüller yükleniyor...</div>
|
||||||
|
<div className="animate-pulse delay-100">> Bağlantı güvenli...</div>
|
||||||
|
<div className="animate-pulse delay-200">> ZeroSixLab hazır.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
46
my-app/src/components/Logo.tsx
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
export const Logo: React.FC<{ size?: 'sm' | 'md' | 'lg' }> = ({ size = 'md' }) => {
|
||||||
|
const [imageError, setImageError] = useState(false);
|
||||||
|
|
||||||
|
const sizeClasses = {
|
||||||
|
sm: 'h-8 w-8',
|
||||||
|
md: 'h-12 w-12',
|
||||||
|
lg: 'h-32 w-32',
|
||||||
|
};
|
||||||
|
|
||||||
|
const textSizes = {
|
||||||
|
sm: 'text-lg',
|
||||||
|
md: 'text-2xl',
|
||||||
|
lg: 'text-5xl',
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-3 select-none group">
|
||||||
|
<div className={`relative rounded-full bg-linear-to-br from-zsl-card to-black p-0.5 border border-zsl-primary/30 group-hover:border-zsl-primary group-hover:shadow-[0_0_15px_rgba(0,212,255,0.4)] transition-all duration-300 ${sizeClasses[size]} overflow-hidden flex items-center justify-center`}>
|
||||||
|
{/* Logo Image - Hidden if error */}
|
||||||
|
{!imageError && (
|
||||||
|
<img
|
||||||
|
src="/assets/logo.png"
|
||||||
|
alt="ZeroSixLab"
|
||||||
|
className="w-full h-full object-cover rounded-full opacity-90 group-hover:opacity-100 transition-opacity"
|
||||||
|
onError={() => setImageError(true)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{/* Fallback CSS Logo - Shown if image fails or not found */}
|
||||||
|
{imageError && (
|
||||||
|
<div className="absolute inset-0 bg-zsl-bg flex items-center justify-center">
|
||||||
|
<div className="absolute left-[25%] top-[40%] w-[20%] h-[20%] rounded-full bg-zsl-primary shadow-[0_0_8px_#00D4FF] flex items-center justify-center text-black font-bold text-[60%] leading-none">0</div>
|
||||||
|
<div className="absolute right-[25%] top-[40%] w-[20%] h-[20%] rounded-full bg-zsl-accent shadow-[0_0_8px_#FFAA00] flex items-center justify-center text-black font-bold text-[60%] leading-none">6</div>
|
||||||
|
<div className="w-[80%] h-[80%] border-2 border-zsl-text/80 rounded-full opacity-30"></div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className={`font-mono font-bold tracking-wider ${textSizes[size]}`}>
|
||||||
|
<span className="text-white">Zero</span>
|
||||||
|
<span className="text-zsl-primary">Six</span>
|
||||||
|
<span className="text-white">Lab</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
142
my-app/src/components/ParticleBackground.tsx
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
interface Particle {
|
||||||
|
id: number;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
size: number;
|
||||||
|
speedX: number;
|
||||||
|
speedY: number;
|
||||||
|
opacity: number;
|
||||||
|
color: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ParticleBackground: React.FC = () => {
|
||||||
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||||
|
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
|
||||||
|
const particlesRef = useRef<Particle[]>([]);
|
||||||
|
const animationRef = useRef<number | undefined>(undefined);
|
||||||
|
const mouseRef = useRef({ x: 0, y: 0 });
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
setDimensions({
|
||||||
|
width: window.innerWidth,
|
||||||
|
height: window.innerHeight
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseMove = (e: MouseEvent) => {
|
||||||
|
mouseRef.current = { x: e.clientX, y: e.clientY };
|
||||||
|
};
|
||||||
|
|
||||||
|
handleResize();
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
window.addEventListener('mousemove', handleMouseMove);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', handleResize);
|
||||||
|
window.removeEventListener('mousemove', handleMouseMove);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const canvas = canvasRef.current;
|
||||||
|
if (!canvas) return;
|
||||||
|
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
if (!ctx) return;
|
||||||
|
|
||||||
|
canvas.width = dimensions.width;
|
||||||
|
canvas.height = dimensions.height;
|
||||||
|
|
||||||
|
// Initialize particles
|
||||||
|
const particleCount = Math.floor((dimensions.width * dimensions.height) / 15000);
|
||||||
|
particlesRef.current = Array.from({ length: particleCount }, (_, i) => ({
|
||||||
|
id: i,
|
||||||
|
x: Math.random() * dimensions.width,
|
||||||
|
y: Math.random() * dimensions.height,
|
||||||
|
size: Math.random() * 2 + 0.5,
|
||||||
|
speedX: (Math.random() - 0.5) * 0.5,
|
||||||
|
speedY: (Math.random() - 0.5) * 0.5,
|
||||||
|
opacity: Math.random() * 0.5 + 0.2,
|
||||||
|
color: Math.random() > 0.7 ? '#FFAA00' : '#00D4FF'
|
||||||
|
}));
|
||||||
|
|
||||||
|
const animate = () => {
|
||||||
|
ctx.clearRect(0, 0, dimensions.width, dimensions.height);
|
||||||
|
|
||||||
|
particlesRef.current.forEach((particle, index) => {
|
||||||
|
// Update position
|
||||||
|
particle.x += particle.speedX;
|
||||||
|
particle.y += particle.speedY;
|
||||||
|
|
||||||
|
// Mouse interaction - particles move away from cursor
|
||||||
|
const dx = mouseRef.current.x - particle.x;
|
||||||
|
const dy = mouseRef.current.y - particle.y;
|
||||||
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
|
if (distance < 100) {
|
||||||
|
const force = (100 - distance) / 100;
|
||||||
|
particle.x -= (dx / distance) * force * 2;
|
||||||
|
particle.y -= (dy / distance) * force * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap around screen
|
||||||
|
if (particle.x < 0) particle.x = dimensions.width;
|
||||||
|
if (particle.x > dimensions.width) particle.x = 0;
|
||||||
|
if (particle.y < 0) particle.y = dimensions.height;
|
||||||
|
if (particle.y > dimensions.height) particle.y = 0;
|
||||||
|
|
||||||
|
// Draw particle
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2);
|
||||||
|
ctx.fillStyle = particle.color.replace(')', `, ${particle.opacity})`).replace('rgb', 'rgba').replace('#', '');
|
||||||
|
|
||||||
|
// Convert hex to rgba
|
||||||
|
const hex = particle.color;
|
||||||
|
const r = parseInt(hex.slice(1, 3), 16);
|
||||||
|
const g = parseInt(hex.slice(3, 5), 16);
|
||||||
|
const b = parseInt(hex.slice(5, 7), 16);
|
||||||
|
ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${particle.opacity})`;
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
// Draw connections between nearby particles
|
||||||
|
particlesRef.current.slice(index + 1).forEach(otherParticle => {
|
||||||
|
const dx = particle.x - otherParticle.x;
|
||||||
|
const dy = particle.y - otherParticle.y;
|
||||||
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
|
if (distance < 120) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(particle.x, particle.y);
|
||||||
|
ctx.lineTo(otherParticle.x, otherParticle.y);
|
||||||
|
ctx.strokeStyle = `rgba(0, 212, 255, ${0.1 * (1 - distance / 120)})`;
|
||||||
|
ctx.lineWidth = 0.5;
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
animationRef.current = requestAnimationFrame(animate);
|
||||||
|
};
|
||||||
|
|
||||||
|
animate();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (animationRef.current) {
|
||||||
|
cancelAnimationFrame(animationRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [dimensions]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<canvas
|
||||||
|
ref={canvasRef}
|
||||||
|
className="fixed inset-0 pointer-events-none z-0"
|
||||||
|
style={{ background: 'transparent' }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
67
my-app/src/components/PartnerLogos.tsx
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface Partner {
|
||||||
|
name: string;
|
||||||
|
logo?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PartnerLogosProps {
|
||||||
|
partners: Partner[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PartnerLogos: React.FC<PartnerLogosProps> = ({ partners }) => {
|
||||||
|
// Duplicate for seamless infinite scroll
|
||||||
|
const duplicatedPartners = [...partners, ...partners];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative overflow-hidden py-8">
|
||||||
|
{/* Gradient masks */}
|
||||||
|
<div className="absolute left-0 top-0 bottom-0 w-32 bg-linear-to-r from-zsl-bg to-transparent z-10" />
|
||||||
|
<div className="absolute right-0 top-0 bottom-0 w-32 bg-linear-to-l from-zsl-bg to-transparent z-10" />
|
||||||
|
|
||||||
|
{/* Scrolling container */}
|
||||||
|
<div className="flex animate-scroll">
|
||||||
|
{duplicatedPartners.map((partner, index) => (
|
||||||
|
<div
|
||||||
|
key={`${partner.name}-${index}`}
|
||||||
|
className="shrink-0 mx-8 md:mx-12"
|
||||||
|
>
|
||||||
|
<div className="w-32 h-16 md:w-40 md:h-20 flex items-center justify-center bg-zsl-card/30 border border-zsl-primary/10 rounded-lg hover:border-zsl-primary/30 transition-all duration-300 group px-4">
|
||||||
|
{partner.logo ? (
|
||||||
|
<img
|
||||||
|
src={partner.logo}
|
||||||
|
alt={partner.name}
|
||||||
|
className="max-w-full max-h-full object-contain opacity-50 group-hover:opacity-100 transition-opacity duration-300 filter grayscale group-hover:grayscale-0"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<span className="text-sm font-medium text-zsl-muted/50 group-hover:text-zsl-primary transition-colors duration-300 text-center">
|
||||||
|
{partner.name}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Add CSS animation */}
|
||||||
|
<style jsx>{`
|
||||||
|
@keyframes scroll {
|
||||||
|
0% {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.animate-scroll {
|
||||||
|
animation: scroll 30s linear infinite;
|
||||||
|
}
|
||||||
|
.animate-scroll:hover {
|
||||||
|
animation-play-state: paused;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
175
my-app/src/components/ProjectModal.tsx
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import Image from 'next/image';
|
||||||
|
|
||||||
|
interface Project {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
longDescription?: string;
|
||||||
|
image: string;
|
||||||
|
technologies: string[];
|
||||||
|
category: string;
|
||||||
|
link?: string;
|
||||||
|
github?: string;
|
||||||
|
features?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ProjectModalProps {
|
||||||
|
project: Project | null;
|
||||||
|
isOpen: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ProjectModal: React.FC<ProjectModalProps> = ({ project, isOpen, onClose }) => {
|
||||||
|
const [isAnimating, setIsAnimating] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isOpen) {
|
||||||
|
setIsAnimating(true);
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
} else {
|
||||||
|
document.body.style.overflow = 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.body.style.overflow = 'auto';
|
||||||
|
};
|
||||||
|
}, [isOpen]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
|
if (e.key === 'Escape' && isOpen) {
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('keydown', handleKeyDown);
|
||||||
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
||||||
|
}, [isOpen, onClose]);
|
||||||
|
|
||||||
|
if (!isOpen || !project) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`fixed inset-0 z-50 flex items-center justify-center p-4 transition-all duration-300 ${isAnimating ? 'opacity-100' : 'opacity-0'}`}
|
||||||
|
onClick={onClose}
|
||||||
|
>
|
||||||
|
{/* Backdrop */}
|
||||||
|
<div className="absolute inset-0 bg-black/80 backdrop-blur-sm" />
|
||||||
|
|
||||||
|
{/* Modal Content */}
|
||||||
|
<div
|
||||||
|
className={`relative bg-zsl-card border border-zsl-primary/20 rounded-2xl max-w-4xl w-full max-h-[90vh] overflow-hidden transition-all duration-300 ${isAnimating ? 'scale-100 translate-y-0' : 'scale-95 translate-y-8'}`}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
{/* Close button */}
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
className="absolute top-4 right-4 z-10 w-10 h-10 rounded-full bg-zsl-bg/80 backdrop-blur-sm border border-zsl-primary/20 flex items-center justify-center text-zsl-muted hover:text-white hover:border-zsl-primary transition-all duration-300"
|
||||||
|
aria-label="Kapat"
|
||||||
|
>
|
||||||
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Scrollable content */}
|
||||||
|
<div className="overflow-y-auto max-h-[90vh]">
|
||||||
|
{/* Hero Image */}
|
||||||
|
<div className="relative h-64 md:h-80 bg-zsl-bg">
|
||||||
|
<div className="absolute inset-0 bg-linear-to-t from-zsl-card to-transparent z-10" />
|
||||||
|
<div className="w-full h-full bg-linear-to-br from-zsl-primary/20 to-zsl-accent/20 flex items-center justify-center">
|
||||||
|
<span className="text-6xl">🚀</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Content */}
|
||||||
|
<div className="p-6 md:p-8 -mt-16 relative z-20">
|
||||||
|
{/* Category Badge */}
|
||||||
|
<span className="inline-block px-3 py-1 text-xs font-medium bg-zsl-primary/20 text-zsl-primary rounded-full mb-4">
|
||||||
|
{project.category}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{/* Title */}
|
||||||
|
<h2 className="text-2xl md:text-3xl font-bold text-white mb-4">
|
||||||
|
{project.title}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
{/* Description */}
|
||||||
|
<p className="text-zsl-muted leading-relaxed mb-6">
|
||||||
|
{project.longDescription || project.description}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* Features */}
|
||||||
|
{project.features && project.features.length > 0 && (
|
||||||
|
<div className="mb-6">
|
||||||
|
<h3 className="text-lg font-semibold text-white mb-3">Özellikler</h3>
|
||||||
|
<ul className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||||
|
{project.features.map((feature, index) => (
|
||||||
|
<li key={index} className="flex items-center gap-2 text-zsl-muted">
|
||||||
|
<svg className="w-4 h-4 text-zsl-primary shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||||
|
</svg>
|
||||||
|
{feature}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Technologies */}
|
||||||
|
<div className="mb-6">
|
||||||
|
<h3 className="text-lg font-semibold text-white mb-3">Teknolojiler</h3>
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{project.technologies.map((tech, index) => (
|
||||||
|
<span
|
||||||
|
key={index}
|
||||||
|
className="px-3 py-1.5 text-sm bg-zsl-bg border border-zsl-primary/20 text-zsl-muted rounded-lg"
|
||||||
|
>
|
||||||
|
{tech}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Action buttons */}
|
||||||
|
<div className="flex flex-wrap gap-4 pt-4 border-t border-zsl-primary/10">
|
||||||
|
{project.link && (
|
||||||
|
<a
|
||||||
|
href={project.link}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="flex items-center gap-2 px-6 py-3 bg-zsl-primary text-zsl-bg font-medium rounded-lg hover:bg-zsl-primary/90 transition-all duration-300"
|
||||||
|
>
|
||||||
|
<svg className="w-5 h-5" 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>
|
||||||
|
Canlı Demo
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
{project.github && (
|
||||||
|
<a
|
||||||
|
href={project.github}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="flex items-center gap-2 px-6 py-3 border border-zsl-primary/30 text-zsl-primary font-medium rounded-lg hover:bg-zsl-primary/10 transition-all duration-300"
|
||||||
|
>
|
||||||
|
<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>
|
||||||
|
GitHub
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Decorative corners */}
|
||||||
|
<div className="absolute top-0 left-0 w-16 h-16 border-t-2 border-l-2 border-zsl-primary/30 rounded-tl-2xl pointer-events-none" />
|
||||||
|
<div className="absolute bottom-0 right-0 w-16 h-16 border-b-2 border-r-2 border-zsl-primary/30 rounded-br-2xl pointer-events-none" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
101
my-app/src/components/ScrollAnimation.tsx
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useEffect, useState, useRef, ReactNode } from 'react';
|
||||||
|
|
||||||
|
interface ScrollAnimationProps {
|
||||||
|
children: ReactNode;
|
||||||
|
animation?: 'fade-up' | 'fade-down' | 'fade-left' | 'fade-right' | 'zoom' | 'flip';
|
||||||
|
delay?: number;
|
||||||
|
duration?: number;
|
||||||
|
threshold?: number;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ScrollAnimation: React.FC<ScrollAnimationProps> = ({
|
||||||
|
children,
|
||||||
|
animation = 'fade-up',
|
||||||
|
delay = 0,
|
||||||
|
duration = 600,
|
||||||
|
threshold = 0.1,
|
||||||
|
className = ''
|
||||||
|
}) => {
|
||||||
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
([entry]) => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
setIsVisible(true);
|
||||||
|
observer.unobserve(entry.target);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ threshold }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ref.current) {
|
||||||
|
observer.observe(ref.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, [threshold]);
|
||||||
|
|
||||||
|
const getAnimationStyles = () => {
|
||||||
|
const baseStyles = {
|
||||||
|
transition: `all ${duration}ms cubic-bezier(0.4, 0, 0.2, 1) ${delay}ms`,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!isVisible) {
|
||||||
|
switch (animation) {
|
||||||
|
case 'fade-up':
|
||||||
|
return { ...baseStyles, opacity: 0, transform: 'translateY(40px)' };
|
||||||
|
case 'fade-down':
|
||||||
|
return { ...baseStyles, opacity: 0, transform: 'translateY(-40px)' };
|
||||||
|
case 'fade-left':
|
||||||
|
return { ...baseStyles, opacity: 0, transform: 'translateX(-40px)' };
|
||||||
|
case 'fade-right':
|
||||||
|
return { ...baseStyles, opacity: 0, transform: 'translateX(40px)' };
|
||||||
|
case 'zoom':
|
||||||
|
return { ...baseStyles, opacity: 0, transform: 'scale(0.8)' };
|
||||||
|
case 'flip':
|
||||||
|
return { ...baseStyles, opacity: 0, transform: 'perspective(1000px) rotateY(90deg)' };
|
||||||
|
default:
|
||||||
|
return { ...baseStyles, opacity: 0 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...baseStyles, opacity: 1, transform: 'none' };
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={ref} style={getAnimationStyles()} className={className}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Hook for custom scroll animations
|
||||||
|
export const useScrollAnimation = (threshold = 0.1) => {
|
||||||
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
([entry]) => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
setIsVisible(true);
|
||||||
|
observer.unobserve(entry.target);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ threshold }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ref.current) {
|
||||||
|
observer.observe(ref.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, [threshold]);
|
||||||
|
|
||||||
|
return { ref, isVisible };
|
||||||
|
};
|
||||||
41
my-app/src/components/ScrollToTop.tsx
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
export const ScrollToTop: React.FC = () => {
|
||||||
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const toggleVisibility = () => {
|
||||||
|
if (window.scrollY > 300) {
|
||||||
|
setIsVisible(true);
|
||||||
|
} else {
|
||||||
|
setIsVisible(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('scroll', toggleVisibility);
|
||||||
|
return () => window.removeEventListener('scroll', toggleVisibility);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const scrollToTop = () => {
|
||||||
|
window.scrollTo({
|
||||||
|
top: 0,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
onClick={scrollToTop}
|
||||||
|
className={`fixed bottom-8 right-8 z-50 p-4 rounded-full bg-zsl-primary text-black shadow-[0_0_20px_rgba(0,212,255,0.4)] hover:bg-white hover:shadow-[0_0_30px_rgba(255,255,255,0.5)] transition-all duration-300 ${
|
||||||
|
isVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10 pointer-events-none'
|
||||||
|
}`}
|
||||||
|
aria-label="Yukarı kaydır"
|
||||||
|
>
|
||||||
|
<svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 10l7-7m0 0l7 7m-7-7v18" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
145
my-app/src/components/TestimonialSlider.tsx
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useState, useEffect, useCallback } from 'react';
|
||||||
|
|
||||||
|
interface Testimonial {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
role: string;
|
||||||
|
company: string;
|
||||||
|
content: string;
|
||||||
|
avatar?: string;
|
||||||
|
rating: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TestimonialSliderProps {
|
||||||
|
testimonials: Testimonial[];
|
||||||
|
autoPlayInterval?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TestimonialSlider: React.FC<TestimonialSliderProps> = ({
|
||||||
|
testimonials,
|
||||||
|
autoPlayInterval = 5000
|
||||||
|
}) => {
|
||||||
|
const [currentIndex, setCurrentIndex] = useState(0);
|
||||||
|
const [isAnimating, setIsAnimating] = useState(false);
|
||||||
|
|
||||||
|
const goToNext = useCallback(() => {
|
||||||
|
if (isAnimating) return;
|
||||||
|
setIsAnimating(true);
|
||||||
|
setCurrentIndex((prev) => (prev + 1) % testimonials.length);
|
||||||
|
setTimeout(() => setIsAnimating(false), 500);
|
||||||
|
}, [isAnimating, testimonials.length]);
|
||||||
|
|
||||||
|
const goToPrev = useCallback(() => {
|
||||||
|
if (isAnimating) return;
|
||||||
|
setIsAnimating(true);
|
||||||
|
setCurrentIndex((prev) => (prev - 1 + testimonials.length) % testimonials.length);
|
||||||
|
setTimeout(() => setIsAnimating(false), 500);
|
||||||
|
}, [isAnimating, testimonials.length]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const interval = setInterval(goToNext, autoPlayInterval);
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, [goToNext, autoPlayInterval]);
|
||||||
|
|
||||||
|
const currentTestimonial = testimonials[currentIndex];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative max-w-4xl mx-auto">
|
||||||
|
{/* Background decoration */}
|
||||||
|
<div className="absolute -top-4 -left-4 text-8xl text-zsl-primary/10 font-serif select-none">"</div>
|
||||||
|
<div className="absolute -bottom-4 -right-4 text-8xl text-zsl-primary/10 font-serif rotate-180 select-none">"</div>
|
||||||
|
|
||||||
|
{/* Main card */}
|
||||||
|
<div className="relative bg-zsl-card/80 backdrop-blur-md border border-zsl-primary/20 rounded-2xl p-8 md:p-12">
|
||||||
|
{/* Content */}
|
||||||
|
<div className={`transition-all duration-500 ${isAnimating ? 'opacity-0 translate-y-4' : 'opacity-100 translate-y-0'}`}>
|
||||||
|
{/* Stars */}
|
||||||
|
<div className="flex gap-1 mb-6">
|
||||||
|
{[...Array(5)].map((_, i) => (
|
||||||
|
<svg
|
||||||
|
key={i}
|
||||||
|
className={`w-5 h-5 ${i < currentTestimonial.rating ? 'text-zsl-accent' : 'text-zsl-muted/30'}`}
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
>
|
||||||
|
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
|
||||||
|
</svg>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Quote */}
|
||||||
|
<p className="text-lg md:text-xl text-white leading-relaxed mb-8">
|
||||||
|
"{currentTestimonial.content}"
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* Author */}
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
{/* Avatar */}
|
||||||
|
<div className="w-14 h-14 rounded-full bg-linear-to-br from-zsl-primary to-zsl-accent p-0.5">
|
||||||
|
<div className="w-full h-full rounded-full bg-zsl-card flex items-center justify-center text-xl font-bold text-zsl-primary">
|
||||||
|
{currentTestimonial.name.charAt(0)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Info */}
|
||||||
|
<div>
|
||||||
|
<div className="font-semibold text-white">{currentTestimonial.name}</div>
|
||||||
|
<div className="text-sm text-zsl-muted">
|
||||||
|
{currentTestimonial.role} • {currentTestimonial.company}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Navigation */}
|
||||||
|
<div className="flex items-center justify-between mt-8 pt-6 border-t border-zsl-primary/10">
|
||||||
|
{/* Arrows */}
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<button
|
||||||
|
onClick={goToPrev}
|
||||||
|
className="w-10 h-10 rounded-full border border-zsl-primary/30 flex items-center justify-center text-zsl-primary hover:bg-zsl-primary hover:text-zsl-bg transition-all duration-300"
|
||||||
|
aria-label="Previous testimonial"
|
||||||
|
>
|
||||||
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={goToNext}
|
||||||
|
className="w-10 h-10 rounded-full border border-zsl-primary/30 flex items-center justify-center text-zsl-primary hover:bg-zsl-primary hover:text-zsl-bg transition-all duration-300"
|
||||||
|
aria-label="Next testimonial"
|
||||||
|
>
|
||||||
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Dots */}
|
||||||
|
<div className="flex gap-2">
|
||||||
|
{testimonials.map((_, index) => (
|
||||||
|
<button
|
||||||
|
key={index}
|
||||||
|
onClick={() => {
|
||||||
|
if (!isAnimating) {
|
||||||
|
setIsAnimating(true);
|
||||||
|
setCurrentIndex(index);
|
||||||
|
setTimeout(() => setIsAnimating(false), 500);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className={`w-2 h-2 rounded-full transition-all duration-300 ${
|
||||||
|
index === currentIndex
|
||||||
|
? 'bg-zsl-primary w-6'
|
||||||
|
: 'bg-zsl-muted/30 hover:bg-zsl-muted/50'
|
||||||
|
}`}
|
||||||
|
aria-label={`Go to testimonial ${index + 1}`}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
20
my-app/src/services/geminiService.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
export const streamChatResponse = async (message: string, history: any[]) => {
|
||||||
|
// Placeholder implementation for Gemini Service
|
||||||
|
// In a real implementation, this would call the Google Generative AI API
|
||||||
|
|
||||||
|
console.log("Streaming chat response for:", message);
|
||||||
|
console.log("History:", history);
|
||||||
|
|
||||||
|
// Simulate a delay and stream
|
||||||
|
return {
|
||||||
|
async *[Symbol.asyncIterator]() {
|
||||||
|
const response = "ZeroSixLab sistemleri şu anda bakım modundadır. Ancak sorgunuz kaydedildi: " + message;
|
||||||
|
const chunks = response.split(" ");
|
||||||
|
|
||||||
|
for (const chunk of chunks) {
|
||||||
|
yield chunk + " ";
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 50 + Math.random() * 50));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
26
my-app/src/types.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export interface Message {
|
||||||
|
id: string;
|
||||||
|
role: 'user' | 'model';
|
||||||
|
text: string;
|
||||||
|
timestamp: Date;
|
||||||
|
isError?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum NavPage {
|
||||||
|
HOME = 'HOME',
|
||||||
|
SERVICES = 'SERVICES', // Solutions
|
||||||
|
PROJECTS = 'PROJECTS', // Lab Results
|
||||||
|
BLOG = 'BLOG', // Lab Notes / Insights
|
||||||
|
ABOUT = 'ABOUT', // The Story
|
||||||
|
LAB = 'LAB', // AI Interface
|
||||||
|
CONTACT = 'CONTACT' // Connect
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FeatureCardProps {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
icon: React.ReactNode;
|
||||||
|
accentColor: 'primary' | 'accent';
|
||||||
|
}
|
||||||
34
my-app/tsconfig.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2017",
|
||||||
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"incremental": true,
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "next"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"next-env.d.ts",
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
".next/types/**/*.ts",
|
||||||
|
".next/dev/types/**/*.ts",
|
||||||
|
"**/*.mts"
|
||||||
|
],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
||||||