Sıfırdan profesyonel admin paneli oluşturma rehberi
- ✅ Template'i kurma ve yapılandırma
- ✅ Komponentleri etkili kullanma
- ✅ Kendi sayfalarınızı oluşturma
- ✅ Tema ve stil özelleştirme
- ✅ AI komponentlerini entegre etme
- ✅ Gerçek veri ile çalışma
- ✅ Production'a deploy etme
# Node.js versiyonunu kontrol edin
node --version # 18.0.0 veya üzeri olmalı
# Package manager seçin
npm --version # veya
yarn --version # veya
bun --version- VS Code (önerilen)
- React Developer Tools (tarayıcı eklentisi)
- Tailwind CSS IntelliSense (VS Code eklentisi)
# 1. Repository'yi klonlayın
git clone https://github.com/sametuca/react19-clapton-admin-template-premium
# 2. Proje dizinine gidin
cd react19-clapton-admin-template
# 3. Bağımlılıkları yükleyin
npm install
# 4. Geliştirme sunucusunu başlatın
npm run dev- Tarayıcıda açın:
http://localhost:8080 - Karşılama sayfasını görün: Modern React 19 karşılama ekranı
- Dashboard'a gidin:
/dashboard- Ana yönetim paneli - Komponentleri keşfedin:
/showcase- Tüm komponentler
src/
├── components/ # Komponentler
│ ├── ui/ # Temel UI komponentleri
│ │ ├── button.tsx # Buton komponenti
│ │ ├── card.tsx # Kart komponenti
│ │ ├── ai/ # AI komponentleri
│ │ └── advanced/ # Gelişmiş komponentler
│ ├── AppSidebar.tsx # Ana sidebar
│ └── ThemeSelector.tsx # Tema seçici
├── pages/ # Sayfa komponentleri
│ ├── Dashboard.tsx # Ana dashboard
│ ├── Welcome.tsx # Karşılama sayfası
│ ├── showcase/ # Komponent vitrin sayfaları
│ └── examples/ # Örnek sayfalar
├── contexts/ # React context'leri
│ ├── ThemeContext.tsx # Tema yönetimi
│ └── LanguageContext.tsx # Dil yönetimi
├── layouts/ # Layout komponentleri
│ └── AppLayout.tsx # Ana layout
└── lib/ # Yardımcı fonksiyonlar
└── utils.ts # Genel yardımcılar
App.tsx: Ana uygulama ve routingmain.tsx: Uygulama giriş noktasıindex.css: Global CSS ve tema değişkenleritailwind.config.ts: Tailwind CSS yapılandırması
// src/pages/MyDashboard.tsx
import { Helmet } from "react-helmet-async";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { StatsCard } from "@/components/ui/stats-card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Users, DollarSign, ShoppingCart, TrendingUp } from "lucide-react";
export default function MyDashboard() {
// Örnek veri
const stats = [
{
title: "Toplam Kullanıcı",
value: 1247,
change: 12.5,
changeType: "positive" as const,
icon: Users,
description: "Bu ay"
},
{
title: "Gelir",
value: 45678,
change: 8.2,
changeType: "positive" as const,
icon: DollarSign,
description: "₺",
prefix: "₺"
},
{
title: "Siparişler",
value: 892,
change: -2.1,
changeType: "negative" as const,
icon: ShoppingCart,
description: "Bekleyen"
},
{
title: "Büyüme",
value: 23.4,
change: 15.7,
changeType: "positive" as const,
icon: TrendingUp,
description: "%",
decimals: 1
}
];
return (
<>
<Helmet>
<title>Benim Dashboard'um - React19 Admin</title>
<meta name="description" content="Özel dashboard sayfası" />
</Helmet>
<div className="space-y-8">
{/* Başlık */}
<div>
<h1 className="text-3xl font-bold tracking-tight">
Benim Dashboard'um
</h1>
<p className="text-muted-foreground mt-1">
Özel dashboard sayfanız
</p>
</div>
{/* İstatistik Kartları */}
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-4">
{stats.map((stat, index) => (
<StatsCard
key={index}
title={stat.title}
value={stat.value}
change={stat.change}
changeType={stat.changeType}
icon={stat.icon}
description={stat.description}
prefix={stat.prefix}
decimals={stat.decimals}
gradient={true}
/>
))}
</div>
{/* İçerik Kartları */}
<div className="grid gap-6 md:grid-cols-2">
<Card>
<CardHeader>
<CardTitle>Son Aktiviteler</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
{[1, 2, 3].map((item) => (
<div key={item} className="flex items-center gap-3 p-3 rounded-lg hover:bg-muted/50 transition-colors">
<div className="w-2 h-2 rounded-full bg-primary" />
<div>
<p className="font-medium">Aktivite {item}</p>
<p className="text-sm text-muted-foreground">
{item} dakika önce
</p>
</div>
</div>
))}
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Hızlı İşlemler</CardTitle>
</CardHeader>
<CardContent className="space-y-3">
<Button className="w-full justify-start">
<Users className="h-4 w-4 mr-2" />
Kullanıcı Ekle
</Button>
<Button variant="outline" className="w-full justify-start">
<ShoppingCart className="h-4 w-4 mr-2" />
Yeni Sipariş
</Button>
<Button variant="secondary" className="w-full justify-start">
<TrendingUp className="h-4 w-4 mr-2" />
Rapor Oluştur
</Button>
</CardContent>
</Card>
</div>
</div>
</>
);
}// src/App.tsx - Routes içine ekleyin
import MyDashboard from "./pages/MyDashboard";
<Route element={<AppLayout />}>
{/* ... mevcut route'lar */}
<Route path="/my-dashboard" element={<MyDashboard />} />
</Route>// src/components/AppSidebar.tsx
const mainItems = [
// ... mevcut öğeler
{
title: "Benim Dashboard'um",
url: "/my-dashboard",
icon: LayoutDashboard,
badge: "Yeni"
},
];// src/pages/UserList.tsx
import { Helmet } from "react-helmet-async";
import { DataTable } from "@/components/ui/data-table";
import { Badge } from "@/components/ui/badge";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import { Edit, Trash2, Eye } from "lucide-react";
export default function UserList() {
// Örnek kullanıcı verisi
const users = [
{
id: 1,
name: "Ahmet Yılmaz",
email: "ahmet@example.com",
role: "Admin",
status: "active",
joinDate: "2024-01-15",
avatar: "/api/placeholder/40/40"
},
{
id: 2,
name: "Zeynep Kaya",
email: "zeynep@example.com",
role: "Editor",
status: "active",
joinDate: "2024-02-20",
avatar: "/api/placeholder/40/40"
},
{
id: 3,
name: "Mehmet Demir",
email: "mehmet@example.com",
role: "User",
status: "inactive",
joinDate: "2024-03-10",
avatar: "/api/placeholder/40/40"
}
];
// Tablo sütunları
const columns = [
{
key: 'avatar' as keyof typeof users[0],
title: 'Kullanıcı',
render: (value: string, row: any) => (
<div className="flex items-center gap-3">
<Avatar className="h-10 w-10">
<AvatarImage src={value} alt={row.name} />
<AvatarFallback>
{row.name.split(' ').map((n: string) => n[0]).join('')}
</AvatarFallback>
</Avatar>
<div>
<div className="font-medium">{row.name}</div>
<div className="text-sm text-muted-foreground">{row.email}</div>
</div>
</div>
)
},
{
key: 'role' as keyof typeof users[0],
title: 'Rol',
render: (value: string) => (
<Badge variant="outline">{value}</Badge>
)
},
{
key: 'status' as keyof typeof users[0],
title: 'Durum',
render: (value: string) => (
<Badge variant={value === 'active' ? 'default' : 'secondary'}>
{value === 'active' ? 'Aktif' : 'Pasif'}
</Badge>
)
},
{
key: 'joinDate' as keyof typeof users[0],
title: 'Katılım Tarihi',
sortable: true
},
{
key: 'id' as keyof typeof users[0],
title: 'İşlemler',
render: (value: number, row: any) => (
<div className="flex items-center gap-2">
<Button size="sm" variant="ghost">
<Eye className="h-4 w-4" />
</Button>
<Button size="sm" variant="ghost">
<Edit className="h-4 w-4" />
</Button>
<Button size="sm" variant="ghost">
<Trash2 className="h-4 w-4" />
</Button>
</div>
)
}
];
return (
<>
<Helmet>
<title>Kullanıcı Listesi - React19 Admin</title>
<meta name="description" content="Kullanıcı yönetimi sayfası" />
</Helmet>
<div className="space-y-6">
<div>
<h1 className="text-3xl font-bold">Kullanıcı Listesi</h1>
<p className="text-muted-foreground">
Tüm kullanıcıları görüntüleyin ve yönetin
</p>
</div>
<DataTable
data={users}
columns={columns}
title="Kullanıcı Yönetimi"
searchable={true}
filterable={true}
exportable={true}
pageSize={10}
/>
</div>
</>
);
}// src/pages/AISearchPage.tsx
import { Helmet } from "react-helmet-async";
import { AISearch } from "@/components/ui/ai/ai-search";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Bot, Search, Sparkles } from "lucide-react";
export default function AISearchPage() {
return (
<>
<Helmet>
<title>AI Arama - React19 Admin</title>
<meta name="description" content="AI destekli akıllı arama sistemi" />
</Helmet>
<div className="space-y-8">
<div className="text-center space-y-4">
<div className="flex items-center justify-center gap-3">
<Bot className="h-8 w-8 text-primary" />
<h1 className="text-3xl font-bold">AI Destekli Arama</h1>
<Badge variant="secondary" className="bg-gradient-to-r from-purple-500 to-blue-500 text-white">
<Sparkles className="h-3 w-3 mr-1" />
AI Powered
</Badge>
</div>
<p className="text-xl text-muted-foreground max-w-2xl mx-auto">
Yapay zeka destekli akıllı arama sistemi ile istediğiniz her şeyi hızlıca bulun
</p>
</div>
<Card className="max-w-4xl mx-auto">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Search className="h-5 w-5" />
Akıllı Arama Sistemi
</CardTitle>
</CardHeader>
<CardContent>
<AISearch />
<div className="mt-8 grid gap-4 md:grid-cols-3">
<div className="text-center p-4 rounded-lg bg-muted/50">
<Search className="h-8 w-8 mx-auto mb-2 text-blue-500" />
<h3 className="font-semibold mb-1">Semantik Arama</h3>
<p className="text-sm text-muted-foreground">
Anlamsal arama ile daha iyi sonuçlar
</p>
</div>
<div className="text-center p-4 rounded-lg bg-muted/50">
<Sparkles className="h-8 w-8 mx-auto mb-2 text-purple-500" />
<h3 className="font-semibold mb-1">Akıllı Öneriler</h3>
<p className="text-sm text-muted-foreground">
AI destekli arama önerileri
</p>
</div>
<div className="text-center p-4 rounded-lg bg-muted/50">
<Bot className="h-8 w-8 mx-auto mb-2 text-green-500" />
<h3 className="font-semibold mb-1">Otomatik Tamamlama</h3>
<p className="text-sm text-muted-foreground">
Yazarken otomatik tamamlama
</p>
</div>
</div>
</CardContent>
</Card>
</div>
</>
);
}// src/layouts/AppLayout.tsx - Layout'a AI Chat ekleyin
import { AIChat } from "@/components/ui/ai/ai-chat";
export default function AppLayout() {
return (
<div className="min-h-screen">
{/* ... mevcut layout içeriği */}
{/* AI Chat - Floating button olarak */}
<AIChat />
</div>
);
}// src/pages/AdvancedAnalytics.tsx
import { Helmet } from "react-helmet-async";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { StatsCard } from "@/components/ui/stats-card";
import { MetricChart } from "@/components/ui/metric-chart";
import { ActivityFeed } from "@/components/ui/activity-feed";
import { AIInsights } from "@/components/ui/ai/ai-insights";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
BarChart3,
TrendingUp,
Users,
Eye,
Download,
Filter,
Calendar,
Globe,
Smartphone,
Monitor
} from "lucide-react";
export default function AdvancedAnalytics() {
const analyticsStats = [
{
title: "Toplam Ziyaretçi",
value: 124847,
change: 15.2,
changeType: "positive" as const,
icon: Users,
description: "Bu ay"
},
{
title: "Sayfa Görüntüleme",
value: 892341,
change: 8.7,
changeType: "positive" as const,
icon: Eye,
description: "Toplam"
},
{
title: "Dönüşüm Oranı",
value: 3.24,
change: 0.8,
changeType: "positive" as const,
icon: TrendingUp,
description: "%",
decimals: 2
},
{
title: "Ortalama Süre",
value: 4.32,
change: -0.5,
changeType: "negative" as const,
icon: BarChart3,
description: "dakika",
decimals: 2
}
];
const chartData = [
{ label: "Ocak", value: 4500, color: "bg-blue-500" },
{ label: "Şubat", value: 5200, color: "bg-green-500" },
{ label: "Mart", value: 4800, color: "bg-purple-500" },
{ label: "Nisan", value: 6100, color: "bg-orange-500" },
{ label: "Mayıs", value: 6800, color: "bg-red-500" },
{ label: "Haziran", value: 7200, color: "bg-indigo-500" }
];
const activities = [
{
id: "1",
user: { name: "Sistem", initials: "SY" },
action: "Yeni rapor oluşturuldu",
target: "Aylık Analiz Raporu",
time: "5 dakika önce",
type: "success" as const,
icon: BarChart3
},
{
id: "2",
user: { name: "Admin", initials: "AD" },
action: "Veri güncellendi",
target: "Kullanıcı İstatistikleri",
time: "15 dakika önce",
type: "info" as const,
icon: Users
}
];
return (
<>
<Helmet>
<title>Gelişmiş Analitik - React19 Admin</title>
<meta name="description" content="AI destekli gelişmiş analitik dashboard" />
</Helmet>
<div className="space-y-8">
{/* Başlık */}
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold tracking-tight">
Gelişmiş Analitik
</h1>
<p className="text-muted-foreground mt-1">
AI destekli analitik ve raporlama
</p>
</div>
<div className="flex items-center gap-2">
<Button variant="outline" size="sm">
<Filter className="h-4 w-4 mr-2" />
Filtrele
</Button>
<Button size="sm">
<Download className="h-4 w-4 mr-2" />
Rapor Al
</Button>
</div>
</div>
{/* İstatistikler */}
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-4">
{analyticsStats.map((stat, index) => (
<StatsCard
key={index}
title={stat.title}
value={stat.value}
change={stat.change}
changeType={stat.changeType}
icon={stat.icon}
description={stat.description}
decimals={stat.decimals}
gradient={true}
/>
))}
</div>
{/* Grafikler ve Aktiviteler */}
<div className="grid gap-8 lg:grid-cols-2">
<MetricChart
title="Aylık Performans"
data={chartData}
total={34400}
change={15.3}
changeType="positive"
/>
<ActivityFeed
activities={activities}
title="Sistem Aktiviteleri"
/>
</div>
{/* AI Insights */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Sparkles className="h-5 w-5 text-purple-500" />
AI Analiz ve Öngörüler
</CardTitle>
</CardHeader>
<CardContent>
<AIInsights />
</CardContent>
</Card>
</div>
</>
);
}// src/contexts/ThemeContext.tsx - themes objesine ekleyin
const themes = {
// ... mevcut temalar
myBrand: {
name: 'Marka Teması',
description: 'Şirket markasına özel tema',
colors: {
background: '0 0% 100%',
foreground: '222.2 84% 4.9%',
primary: '346.8 77.2% 49.8%', // Marka kırmızısı
'primary-foreground': '355.7 100% 97.3%',
secondary: '220.9 39.3% 11%',
'secondary-foreground': '210 40% 98%',
accent: '346.8 77.2% 49.8%',
'accent-foreground': '355.7 100% 97.3%',
// ... diğer renkler
},
gradient: 'linear-gradient(135deg, #ff6b6b 0%, #ee5a24 25%, #ff9ff3 50%, #54a0ff 75%, #5f27cd 100%)'
}
};/* src/index.css - Özel tema stilleri */
.theme-myBrand body {
background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 25%, #ff9ff3 50%, #54a0ff 75%, #5f27cd 100%);
background-attachment: fixed;
}
.theme-myBrand .glassmorphism-card {
background: rgba(255, 107, 107, 0.08);
backdrop-filter: blur(25px);
border: 1px solid rgba(255, 107, 107, 0.3);
box-shadow:
0 8px 32px 0 rgba(255, 107, 107, 0.3),
inset 0 1px 0 rgba(255, 107, 107, 0.2);
}
.theme-myBrand .gradient-text-primary {
background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}// src/hooks/use-api.ts
import { useState, useEffect } from 'react';
interface ApiResponse<T> {
data: T | null;
loading: boolean;
error: string | null;
refetch: () => void;
}
export function useApi<T>(url: string): ApiResponse<T> {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const fetchData = async () => {
try {
setLoading(true);
setError(null);
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
setData(result);
} catch (err) {
setError(err instanceof Error ? err.message : 'Bir hata oluştu');
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchData();
}, [url]);
return { data, loading, error, refetch: fetchData };
}// src/pages/UsersFromAPI.tsx
import { useApi } from '@/hooks/use-api';
import { LoadingSpinner } from '@/components/ui/loading-spinner';
import { Alert, AlertDescription } from '@/components/ui/alert';
export default function UsersFromAPI() {
const { data: users, loading, error, refetch } = useApi<User[]>('/api/users');
if (loading) {
return (
<div className="flex justify-center py-12">
<LoadingSpinner size="lg" text="Kullanıcılar yükleniyor..." />
</div>
);
}
if (error) {
return (
<Alert variant="destructive">
<AlertDescription>
Hata: {error}
<Button onClick={refetch} className="ml-2" size="sm">
Tekrar Dene
</Button>
</AlertDescription>
</Alert>
);
}
return (
<div>
<DataTable
data={users || []}
columns={userColumns}
title="API'den Kullanıcılar"
searchable={true}
exportable={true}
/>
</div>
);
}// src/pages/UserForm.tsx
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import * as z from 'zod';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { toast } from '@/hooks/use-toast';
const formSchema = z.object({
name: z.string().min(2, 'Ad en az 2 karakter olmalı'),
email: z.string().email('Geçerli bir e-posta adresi girin'),
role: z.string().min(1, 'Rol seçimi zorunlu'),
department: z.string().min(1, 'Departman seçimi zorunlu'),
});
type FormData = z.infer<typeof formSchema>;
export default function UserForm() {
const form = useForm<FormData>({
resolver: zodResolver(formSchema),
defaultValues: {
name: '',
email: '',
role: '',
department: '',
},
});
const onSubmit = async (data: FormData) => {
try {
// API çağrısı simülasyonu
await new Promise(resolve => setTimeout(resolve, 1000));
toast({
title: "Başarılı!",
description: "Kullanıcı başarıyla eklendi.",
});
form.reset();
} catch (error) {
toast({
title: "Hata!",
description: "Kullanıcı eklenirken bir hata oluştu.",
variant: "destructive",
});
}
};
return (
<Card className="max-w-2xl mx-auto">
<CardHeader>
<CardTitle>Yeni Kullanıcı Ekle</CardTitle>
</CardHeader>
<CardContent>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
<div className="grid gap-4 md:grid-cols-2">
<div className="space-y-2">
<Label htmlFor="name">Ad Soyad</Label>
<Input
id="name"
{...form.register('name')}
placeholder="Ahmet Yılmaz"
/>
{form.formState.errors.name && (
<p className="text-sm text-red-500">
{form.formState.errors.name.message}
</p>
)}
</div>
<div className="space-y-2">
<Label htmlFor="email">E-posta</Label>
<Input
id="email"
type="email"
{...form.register('email')}
placeholder="ahmet@example.com"
/>
{form.formState.errors.email && (
<p className="text-sm text-red-500">
{form.formState.errors.email.message}
</p>
)}
</div>
</div>
<div className="grid gap-4 md:grid-cols-2">
<div className="space-y-2">
<Label>Rol</Label>
<Select onValueChange={(value) => form.setValue('role', value)}>
<SelectTrigger>
<SelectValue placeholder="Rol seçin" />
</SelectTrigger>
<SelectContent>
<SelectItem value="admin">Admin</SelectItem>
<SelectItem value="editor">Editör</SelectItem>
<SelectItem value="user">Kullanıcı</SelectItem>
</SelectContent>
</Select>
{form.formState.errors.role && (
<p className="text-sm text-red-500">
{form.formState.errors.role.message}
</p>
)}
</div>
<div className="space-y-2">
<Label>Departman</Label>
<Select onValueChange={(value) => form.setValue('department', value)}>
<SelectTrigger>
<SelectValue placeholder="Departman seçin" />
</SelectTrigger>
<SelectContent>
<SelectItem value="it">Bilgi İşlem</SelectItem>
<SelectItem value="hr">İnsan Kaynakları</SelectItem>
<SelectItem value="sales">Satış</SelectItem>
<SelectItem value="marketing">Pazarlama</SelectItem>
</SelectContent>
</Select>
{form.formState.errors.department && (
<p className="text-sm text-red-500">
{form.formState.errors.department.message}
</p>
)}
</div>
</div>
<div className="flex justify-end gap-4">
<Button type="button" variant="outline" onClick={() => form.reset()}>
Temizle
</Button>
<Button
type="submit"
disabled={form.formState.isSubmitting}
>
{form.formState.isSubmitting ? 'Kaydediliyor...' : 'Kaydet'}
</Button>
</div>
</form>
</CardContent>
</Card>
);
}# .env.production
NODE_ENV=production
VITE_APP_NAME=Sizin Uygulama Adınız
VITE_API_URL=https://api.yourdomain.com
VITE_AUTH_DOMAIN=auth.yourdomain.com// vite.config.ts
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
ui: ['@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu'],
charts: ['recharts'],
},
},
},
},
});// Her sayfada Helmet kullanın
<Helmet>
<title>Sayfa Başlığı - Uygulama Adı</title>
<meta name="description" content="Sayfa açıklaması" />
<meta property="og:title" content="Sayfa Başlığı" />
<meta property="og:description" content="Sayfa açıklaması" />
<link rel="canonical" href="https://yourdomain.com/page" />
</Helmet>// Mobil-first yaklaşım
function ResponsiveCard() {
return (
<Card className="
p-4 /* Mobil: küçük padding */
md:p-6 /* Tablet: orta padding */
lg:p-8 /* Desktop: büyük padding */
text-sm /* Mobil: küçük metin */
md:text-base /* Tablet: normal metin */
lg:text-lg /* Desktop: büyük metin */
">
<CardContent className="
space-y-2 /* Mobil: az boşluk */
md:space-y-4 /* Tablet: orta boşluk */
lg:space-y-6 /* Desktop: çok boşluk */
">
{/* İçerik */}
</CardContent>
</Card>
);
}// src/components/AppSidebar.tsx - Mobil menü zaten mevcut
// Özelleştirmek için:
const [isMobileOpen, setIsMobileOpen] = useState(false);
// Mobil menü butonu
<Button
variant="ghost"
size="icon"
onClick={() => setIsMobileOpen(!isMobileOpen)}
className="lg:hidden"
>
<Menu className="h-5 w-5" />
</Button>// src/contexts/AuthContext.tsx
import React, { createContext, useContext, useState } from 'react';
interface User {
id: string;
name: string;
email: string;
role: string;
}
interface AuthContextType {
user: User | null;
login: (email: string, password: string) => Promise<void>;
logout: () => void;
loading: boolean;
}
const AuthContext = createContext<AuthContextType | undefined>(undefined);
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(false);
const login = async (email: string, password: string) => {
setLoading(true);
try {
// API çağrısı
const response = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
});
const userData = await response.json();
setUser(userData);
// Token'ı localStorage'a kaydet
localStorage.setItem('token', userData.token);
} catch (error) {
throw error;
} finally {
setLoading(false);
}
};
const logout = () => {
setUser(null);
localStorage.removeItem('token');
};
return (
<AuthContext.Provider value={{ user, login, logout, loading }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within AuthProvider');
}
return context;
}// src/components/ProtectedRoute.tsx
import { useAuth } from '@/contexts/AuthContext';
import { Navigate } from 'react-router-dom';
import { LoadingSpinner } from '@/components/ui/loading-spinner';
interface ProtectedRouteProps {
children: React.ReactNode;
requiredRole?: string;
}
export function ProtectedRoute({ children, requiredRole }: ProtectedRouteProps) {
const { user, loading } = useAuth();
if (loading) {
return (
<div className="flex justify-center items-center min-h-screen">
<LoadingSpinner size="lg" text="Yetkilendirme kontrol ediliyor..." />
</div>
);
}
if (!user) {
return <Navigate to="/login" replace />;
}
if (requiredRole && user.role !== requiredRole) {
return <Navigate to="/unauthorized" replace />;
}
return <>{children}</>;
}// src/services/api.ts
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000/api';
class ApiService {
private async request<T>(endpoint: string, options?: RequestInit): Promise<T> {
const token = localStorage.getItem('token');
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
headers: {
'Content-Type': 'application/json',
...(token && { Authorization: `Bearer ${token}` }),
...options?.headers,
},
...options,
});
if (!response.ok) {
throw new Error(`API Error: ${response.status}`);
}
return response.json();
}
// Kullanıcı işlemleri
async getUsers() {
return this.request<User[]>('/users');
}
async createUser(userData: Partial<User>) {
return this.request<User>('/users', {
method: 'POST',
body: JSON.stringify(userData),
});
}
async updateUser(id: string, userData: Partial<User>) {
return this.request<User>(`/users/${id}`, {
method: 'PUT',
body: JSON.stringify(userData),
});
}
async deleteUser(id: string) {
return this.request<void>(`/users/${id}`, {
method: 'DELETE',
});
}
// Dashboard istatistikleri
async getDashboardStats() {
return this.request<DashboardStats>('/dashboard/stats');
}
}
export const apiService = new ApiService();// src/pages/RealDataDashboard.tsx
import { useEffect, useState } from 'react';
import { apiService } from '@/services/api';
import { StatsCard } from '@/components/ui/stats-card';
import { LoadingSpinner } from '@/components/ui/loading-spinner';
export default function RealDataDashboard() {
const [stats, setStats] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchStats = async () => {
try {
const data = await apiService.getDashboardStats();
setStats(data);
} catch (error) {
console.error('Stats yüklenemedi:', error);
} finally {
setLoading(false);
}
};
fetchStats();
}, []);
if (loading) {
return (
<div className="flex justify-center py-12">
<LoadingSpinner size="lg" text="Dashboard yükleniyor..." />
</div>
);
}
return (
<div className="space-y-6">
<h1 className="text-3xl font-bold">Gerçek Veri Dashboard</h1>
{stats && (
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-4">
<StatsCard
title="Toplam Kullanıcı"
value={stats.totalUsers}
change={stats.userGrowth}
changeType="positive"
icon={Users}
/>
{/* ... diğer istatistikler */}
</div>
)}
</div>
);
}import { Card3D, ImageCard3D } from '@/components/ui/3d-card';
function Premium3DPage() {
return (
<div className="grid gap-8 md:grid-cols-3">
<Card3D intensity={25} scale={1.1}>
<Card className="h-64">
<CardContent className="p-6">
<h3 className="text-xl font-bold mb-2">3D Kart</h3>
<p>Mouse ile üzerine gelin!</p>
</CardContent>
</Card>
</Card3D>
<ImageCard3D
image="https://images.unsplash.com/photo-1551434678-e076c223a692?w=400&h=300&fit=crop"
title="Premium Dashboard"
description="Gelişmiş admin paneli"
badge="Yeni"
/>
</div>
);
}import { GlassmorphismCard } from '@/components/ui/glassmorphism-card';
function GlassEffectsPage() {
return (
<div className="grid gap-6 md:grid-cols-3">
<GlassmorphismCard
title="Analytics"
description="Gelişmiş analitik araçları"
icon={BarChart3}
variant="primary"
blur="lg"
>
<div className="space-y-3">
<div className="flex justify-between">
<span>Performans</span>
<span className="font-semibold">95%</span>
</div>
<Progress value={95} />
</div>
</GlassmorphismCard>
</div>
);
}# 1. Build alın
npm run build
# 2. Netlify CLI yükleyin (opsiyonel)
npm i -g netlify-cli
# 3. Deploy edin
netlify deploy --prod --dir=dist# Netlify
netlify env:set VITE_API_URL https://api.yourdomain.com# Güncel olmayan paketleri kontrol edin
npm outdated
# Güvenlik açıklarını kontrol edin
npm audit
# Paketleri güncelleyin
npm update
# Major güncellemeler için
npx npm-check-updates -u
npm install// src/utils/performance.ts
export function measurePerformance(name: string, fn: () => void) {
const start = performance.now();
fn();
const end = performance.now();
console.log(`${name} took ${end - start} milliseconds`);
}
// Kullanım
measurePerformance('Component Render', () => {
// Komponent render işlemi
});// src/components/ErrorBoundary.tsx
import React from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { AlertTriangle } from 'lucide-react';
interface ErrorBoundaryState {
hasError: boolean;
error?: Error;
}
export class ErrorBoundary extends React.Component<
React.PropsWithChildren<{}>,
ErrorBoundaryState
> {
constructor(props: React.PropsWithChildren<{}>) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error('Error caught by boundary:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return (
<div className="min-h-screen flex items-center justify-center p-4">
<Card className="max-w-md w-full">
<CardHeader className="text-center">
<AlertTriangle className="h-12 w-12 text-red-500 mx-auto mb-4" />
<CardTitle>Bir Hata Oluştu</CardTitle>
</CardHeader>
<CardContent className="text-center space-y-4">
<p className="text-muted-foreground">
Beklenmeyen bir hata oluştu. Lütfen sayfayı yenileyin.
</p>
<Button onClick={() => window.location.reload()}>
Sayfayı Yenile
</Button>
</CardContent>
</Card>
</div>
);
}
return this.props.children;
}
}// ✅ İyi: Tek sorumluluk prensibi
function UserCard({ user }: { user: User }) {
return (
<Card>
<CardContent>
<h3>{user.name}</h3>
<p>{user.email}</p>
</CardContent>
</Card>
);
}
// ✅ İyi: Custom hook kullanımı
function useUsers() {
const [users, setUsers] = useState<User[]>([]);
const [loading, setLoading] = useState(true);
// ... logic
return { users, loading, refetch };
}
// ✅ İyi: Type safety
interface UserListProps {
users: User[];
onUserSelect: (user: User) => void;
loading?: boolean;
}// ✅ Lazy loading
const HeavyComponent = lazy(() => import('./HeavyComponent'));
// ✅ Memoization
const ExpensiveComponent = memo(function ExpensiveComponent({ data }) {
const processedData = useMemo(() => {
return heavyProcessing(data);
}, [data]);
return <div>{processedData}</div>;
});
// ✅ Callback optimization
const MyComponent = ({ onSave }: { onSave: (data: any) => void }) => {
const handleSave = useCallback((data) => {
onSave(data);
}, [onSave]);
return <Button onClick={() => handleSave(data)}>Save</Button>;
};// src/utils/analytics.ts
declare global {
interface Window {
gtag: (...args: any[]) => void;
}
}
export function trackEvent(action: string, category: string, label?: string) {
if (typeof window !== 'undefined' && window.gtag) {
window.gtag('event', action, {
event_category: category,
event_label: label,
});
}
}
// Kullanım
trackEvent('click', 'button', 'header-cta');// src/utils/errorTracking.ts
export function logError(error: Error, context?: string) {
console.error('Error:', error, 'Context:', context);
// Sentry, LogRocket vb. servislere gönder
if (import.meta.env.PROD) {
// Production'da error tracking servisine gönder
}
}- ✅ Template kurulumu ve yapılandırması
- ✅ Temel sayfa oluşturma
- ✅ Komponent kullanımı
- ✅ Tema özelleştirme
- ✅ API entegrasyonu
- ✅ Form oluşturma
- ✅ Responsive tasarım
- ✅ Production deployment
- State Management: Redux Toolkit, Zustand
- Testing: Jest, React Testing Library
- E2E Testing: Playwright, Cypress
- Monitoring: Sentry, LogRocket
- CI/CD: GitHub Actions, GitLab CI
- 📧 Premium Destek: support@clapton-admin.com
- 💬 Discord Topluluğu: discord.gg/clapton-admin
- 📖 Dokümantasyon: docs.clapton-admin.com
- 🎥 Video Tutorials: youtube.com/@clapton-admin
Bu tutorial'ı tamamladığınız için tebrikler! Artık React 19 Clapton Admin Template ile profesyonel admin panelleri oluşturabilirsiniz.
- 🥇 Template Master: Template'i başarıyla kurdunuz
- 🥈 Component Expert: Komponentleri etkili kullanıyorsunuz
- 🥉 Theme Designer: Tema özelleştirmesi yapabiliyorsunuz
- 🏆 Full Stack: API entegrasyonu tamamladınız
- 💎 Production Ready: Deploy sürecini öğrendiniz
- Kendi Projenizi Başlatın: Öğrendiklerinizi gerçek projede uygulayın
- Toplulukla Paylaşın: Yaptığınız projeleri toplulukla paylaşın
- Katkıda Bulunun: Template'e katkıda bulunun ve geliştirin
- Öğretmeye Başlayın: Bilginizi başkalarıyla paylaşın
Başarılı projeler dileriz! 🚀
Made with ❤️ by Clapton Team