feat: implement dashboard layout with sidebar navigation, finance page, and supporting UI architecture

This commit is contained in:
Poyraz Avsever
2026-05-08 14:12:26 +03:00
parent e0a2dace49
commit a21c64172e
7 changed files with 921 additions and 422 deletions
+255
View File
@@ -0,0 +1,255 @@
"use client";
import { Search, Filter, Brain, ArrowUpRight, ArrowDownRight, DollarSign, Activity, PieChart, Download, Wallet, Plus } from "lucide-react";
import {
Bar,
BarChart,
CartesianGrid,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
Area,
AreaChart,
Pie,
PieChart as RechartsPieChart,
Cell
} from "recharts";
// Mock Data
const cashFlowData = [
{ month: "Jan", in: 45000, out: 28000 },
{ month: "Feb", in: 52000, out: 31000 },
{ month: "Mar", in: 48000, out: 29000 },
{ month: "Apr", in: 61000, out: 34000 },
{ month: "May", in: 59000, out: 42000 },
{ month: "Jun", in: 75000, out: 38000 },
];
const expensesData = [
{ name: "Payroll", value: 45000, color: "#6C5BB0" },
{ name: "Software/SaaS", value: 12000, color: "#54468B" },
{ name: "Marketing", value: 18000, color: "#3B3161" },
{ name: "Office/Rent", value: 8000, color: "#221C38" },
];
const recentTransactions = [
{ id: 1, desc: "Stripe Payout", category: "Revenue", amount: "+$12,450.00", date: "Today", status: "Completed" },
{ id: 2, desc: "Amazon Web Services", category: "Software", amount: "-$3,240.50", date: "Yesterday", status: "Completed" },
{ id: 3, desc: "Google Ads", category: "Marketing", amount: "-$4,500.00", date: "May 15", status: "Pending" },
{ id: 4, desc: "WeWork Remote", category: "Office", amount: "-$1,200.00", date: "May 12", status: "Completed" },
];
export default function FinancePage() {
return (
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6">
{/* Top Header */}
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4">
<h1 className="text-lg font-medium text-muted-foreground">
<span className="text-foreground">Management</span> / Finance
</h1>
<div className="flex items-center gap-3">
<button className="bg-white/5 hover:bg-white/10 text-foreground border border-white/10 px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
<Download className="h-4 w-4" />
STATEMENT
</button>
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
<Plus className="h-4 w-4" />
NEW INVOICE
</button>
</div>
</div>
{/* AI Financial Analyst */}
<div className="rounded-sm border border-primary/20 bg-primary/5 p-6 flex flex-col md:flex-row items-start md:items-center justify-between gap-6">
<div className="flex items-start gap-4">
<div className="p-3 bg-primary/10 rounded-sm shrink-0">
<Brain className="h-6 w-6 text-primary" />
</div>
<div>
<h3 className="text-sm font-semibold text-primary mb-1 flex items-center gap-2">
AI Financial Analyst
</h3>
<p className="text-xs text-foreground/80 leading-relaxed max-w-3xl">
I detected an anomaly: <strong>Software/SaaS expenses</strong> increased by 22% compared to last month. Specifically, AWS costs spiked. AI recommends auditing idle EC2 instances to save approximately $850/mo.
</p>
</div>
</div>
<button className="bg-primary/20 text-primary hover:bg-primary/30 border border-primary/30 px-4 py-2 rounded-sm text-xs font-semibold transition-colors shrink-0">
Run Cloud Audit
</button>
</div>
{/* KPI Row */}
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6">
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-6">
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-4 flex items-center gap-2">
<DollarSign className="h-3.5 w-3.5" /> Total Revenue (MTD)
</h3>
<div className="flex items-end gap-3 mb-1">
<span className="text-3xl font-bold text-foreground">$124,500</span>
<span className="text-xs text-emerald-500 flex items-center font-medium mb-1">
<ArrowUpRight className="h-3 w-3 mr-0.5" /> 8.4%
</span>
</div>
</div>
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-6">
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-4 flex items-center gap-2">
<Activity className="h-3.5 w-3.5" /> Monthly Burn Rate
</h3>
<div className="flex items-end gap-3 mb-1">
<span className="text-3xl font-bold text-foreground">$42,300</span>
<span className="text-xs text-red-500 flex items-center font-medium mb-1">
<ArrowUpRight className="h-3 w-3 mr-0.5" /> 2.1%
</span>
</div>
</div>
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-6">
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-4 flex items-center gap-2">
<Wallet className="h-3.5 w-3.5" /> Cash Runway
</h3>
<div className="flex items-end gap-3 mb-1">
<span className="text-3xl font-bold text-foreground">14.2</span>
<span className="text-xs text-muted-foreground flex items-center font-medium mb-1">
Months
</span>
</div>
</div>
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-6">
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-4 flex items-center gap-2">
<Brain className="h-3.5 w-3.5 text-primary" /> AI Profitability Score
</h3>
<div className="flex items-end gap-3 mb-1">
<span className="text-3xl font-bold text-primary">94/100</span>
<span className="text-xs text-emerald-500 flex items-center font-medium mb-1">
Optimal
</span>
</div>
</div>
</div>
{/* Charts & Tables */}
<div className="grid grid-cols-1 xl:grid-cols-3 gap-6 flex-1 min-h-[400px]">
{/* Cash Flow Chart */}
<div className="xl:col-span-2 rounded-sm border border-white/5 bg-[#0A0710] p-6 flex flex-col">
<div className="flex justify-between items-start mb-6">
<div>
<h3 className="text-sm font-semibold mb-1">Cash Flow Overview</h3>
<p className="text-xs text-muted-foreground">Revenue vs Expenses over the last 6 months.</p>
</div>
<div className="flex gap-4 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
<div className="flex items-center gap-2"><div className="w-2 h-2 rounded-sm bg-emerald-500"></div> Inflow</div>
<div className="flex items-center gap-2"><div className="w-2 h-2 rounded-sm bg-red-500"></div> Outflow</div>
</div>
</div>
<div className="flex-1 w-full min-h-[250px]">
<ResponsiveContainer width="100%" height="100%">
<BarChart data={cashFlowData}>
<CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#ffffff05" />
<XAxis dataKey="month" axisLine={false} tickLine={false} tick={{ fontSize: 11, fill: '#8F89A5' }} dy={10} />
<YAxis axisLine={false} tickLine={false} tick={{ fontSize: 11, fill: '#8F89A5' }} dx={-10} tickFormatter={(val) => `$${val/1000}k`} />
<Tooltip
cursor={{ fill: '#ffffff05' }}
contentStyle={{ backgroundColor: "#1F172B", border: "none", fontSize: "12px", color: "#FBF9FE", borderRadius: "4px" }}
itemStyle={{ color: "#FBF9FE" }}
/>
<Bar dataKey="in" fill="#10b981" radius={[2, 2, 0, 0]} barSize={16} />
<Bar dataKey="out" fill="#ef4444" radius={[2, 2, 0, 0]} barSize={16} />
</BarChart>
</ResponsiveContainer>
</div>
</div>
{/* Expenses Pie & Recent Transactions */}
<div className="flex flex-col gap-6">
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-6 flex-1 flex flex-col">
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-2">Expenses Breakdown</h3>
<div className="flex-1 w-full flex items-center justify-center relative min-h-[160px]">
<ResponsiveContainer width="100%" height="100%">
<RechartsPieChart>
<Pie
data={expensesData}
cx="50%"
cy="50%"
innerRadius={50}
outerRadius={70}
paddingAngle={2}
dataKey="value"
stroke="none"
>
{expensesData.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} />
))}
</Pie>
<Tooltip contentStyle={{ backgroundColor: "#1F172B", border: "none", fontSize: "12px" }} />
</RechartsPieChart>
</ResponsiveContainer>
<div className="absolute inset-0 flex items-center justify-center pointer-events-none flex-col">
<span className="text-[10px] text-muted-foreground uppercase font-bold tracking-widest">Total</span>
<span className="text-sm font-bold">$83k</span>
</div>
</div>
<div className="space-y-2 mt-4">
{expensesData.map((item, idx) => (
<div key={idx} className="flex justify-between items-center text-xs">
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-sm" style={{ backgroundColor: item.color }}></div>
<span className="text-muted-foreground">{item.name}</span>
</div>
<span className="font-semibold">${(item.value / 1000).toFixed(1)}k</span>
</div>
))}
</div>
</div>
</div>
</div>
{/* AI Categorized Transactions */}
<div className="bg-[#0A0710] rounded-sm border border-white/5 overflow-hidden">
<div className="p-4 border-b border-white/5 flex justify-between items-center">
<h3 className="text-sm font-semibold">Recent Transactions</h3>
<span className="text-[10px] font-bold uppercase tracking-wider text-primary flex items-center gap-1"><Brain className="h-3 w-3" /> Auto-Categorized by AI</span>
</div>
<div className="grid grid-cols-12 gap-4 p-4 border-b border-white/5 bg-[#0F0B15]/50 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
<div className="col-span-5">Description</div>
<div className="col-span-2">Category</div>
<div className="col-span-2">Date</div>
<div className="col-span-2">Amount</div>
<div className="col-span-1 text-right">Status</div>
</div>
<div className="divide-y divide-white/5">
{recentTransactions.map((tx) => (
<div key={tx.id} className="grid grid-cols-12 gap-4 p-4 items-center hover:bg-white/[0.02] transition-colors">
<div className="col-span-5 text-sm font-medium">{tx.desc}</div>
<div className="col-span-2 text-xs text-muted-foreground">{tx.category}</div>
<div className="col-span-2 text-xs text-muted-foreground">{tx.date}</div>
<div className={`col-span-2 text-sm font-bold ${tx.amount.startsWith('+') ? 'text-emerald-400' : 'text-foreground'}`}>
{tx.amount}
</div>
<div className="col-span-1 text-right">
<span className={`text-[10px] uppercase font-bold px-2 py-1 rounded-sm border inline-block ${
tx.status === 'Completed' ? 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20' :
'bg-orange-500/10 text-orange-400 border-orange-500/20'
}`}>
{tx.status}
</span>
</div>
</div>
))}
</div>
</div>
</div>
);
}
+157 -9
View File
@@ -1,17 +1,165 @@
"use client";
import { Plus, Brain, Target, Compass, Award, MoreHorizontal, CircleDashed, CheckCircle2 } from "lucide-react";
// Mock Data
const goals = [
{
id: 1,
title: "Launch SaaS Product MVP",
category: "Career & Business",
progress: 75,
dueDate: "Q3 2026",
status: "On Track",
color: "#6C5BB0", // Primary
milestones: [
{ name: "Finalize Designs", done: true },
{ name: "Backend Architecture", done: true },
{ name: "Frontend Development", done: true },
{ name: "Beta Testing", done: false },
{ name: "Public Launch", done: false },
]
},
{
id: 2,
title: "Run a Half-Marathon",
category: "Health & Fitness",
progress: 40,
dueDate: "Oct 12, 2026",
status: "Behind",
color: "#10b981", // Emerald
milestones: [
{ name: "Run 5K Without Stopping", done: true },
{ name: "Run 10K", done: true },
{ name: "Maintain 15K weekly volume", done: false },
{ name: "Complete 18K long run", done: false },
]
},
{
id: 3,
title: "Read 24 Books",
category: "Personal Growth",
progress: 50,
dueDate: "Dec 31, 2026",
status: "Ahead",
color: "#f97316", // Orange
milestones: [
{ name: "Read 6 Books (Q1)", done: true },
{ name: "Read 12 Books (Q2)", done: true },
{ name: "Read 18 Books (Q3)", done: false },
]
}
];
export default function GoalsPage() {
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold tracking-tight text-foreground">Hedefler</h1>
<p className="text-muted-foreground mt-2">
Kısa ve uzun vadeli hedeflerinizi belirleyin ve ilerlemenizi izleyin.
</p>
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6">
{/* Top Header */}
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4">
<h1 className="text-lg font-medium text-muted-foreground">
<span className="text-foreground">Personal</span> / Strategic Goals
</h1>
<div className="flex items-center gap-3">
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
<Plus className="h-4 w-4" />
NEW GOAL
</button>
</div>
</div>
<div className="rounded-2xl border border-white/5 bg-white/5 p-8 text-center text-muted-foreground backdrop-blur-sm">
Hedef yönetim modülü yakında eklenecek.
{/* AI Goal Strategist */}
<div className="rounded-sm border border-primary/20 bg-primary/5 p-6 flex flex-col md:flex-row items-center justify-between gap-6">
<div className="flex items-start gap-4">
<div className="p-3 bg-primary/10 rounded-sm shrink-0">
<Brain className="h-6 w-6 text-primary" />
</div>
<div>
<h3 className="text-sm font-semibold text-primary mb-1 flex items-center gap-2">
AI Goal Strategist
</h3>
<p className="text-xs text-foreground/80 leading-relaxed max-w-3xl">
You are falling behind on your <strong>Half-Marathon</strong> goal. Your running habit completion has dropped to 30% this month. AI suggests breaking the next milestone ("Maintain 15K weekly volume") into smaller, manageable 3K chunks to rebuild momentum.
</p>
</div>
</div>
<button className="bg-primary hover:bg-primary/90 text-primary-foreground px-4 py-2 rounded-sm text-xs font-semibold transition-colors shrink-0 shadow-lg shadow-primary/20">
Refactor Milestones
</button>
</div>
{/* Goals List */}
<div className="space-y-6 pb-6">
{goals.map((goal) => (
<div key={goal.id} className="rounded-sm border border-white/5 bg-[#0A0710] p-6 flex flex-col lg:flex-row gap-8 relative overflow-hidden group">
{/* Left Side: Overview & Progress */}
<div className="flex-1 flex flex-col justify-between">
<div>
<div className="flex items-center gap-3 mb-2">
<h2 className="text-xl font-bold text-foreground">{goal.title}</h2>
<span className={`text-[10px] uppercase font-bold px-2 py-0.5 rounded-sm border ${
goal.status === 'Ahead' ? 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20' :
goal.status === 'Behind' ? 'bg-orange-500/10 text-orange-400 border-orange-500/20' :
'bg-blue-500/10 text-blue-400 border-blue-500/20'
}`}>
{goal.status}
</span>
</div>
<div className="flex items-center gap-4 text-xs text-muted-foreground mb-6">
<span className="flex items-center gap-1.5"><Compass className="h-3.5 w-3.5" /> {goal.category}</span>
<span className="flex items-center gap-1.5"><Target className="h-3.5 w-3.5" /> Due: {goal.dueDate}</span>
</div>
</div>
{/* Big Progress Bar */}
<div>
<div className="flex justify-between items-end mb-2">
<span className="text-sm font-semibold">Overall Progress</span>
<span className="text-2xl font-bold" style={{ color: goal.color }}>{goal.progress}%</span>
</div>
<div className="h-3 w-full bg-white/5 rounded-full overflow-hidden">
<div
className="h-full rounded-full transition-all duration-1000 relative"
style={{ width: `${goal.progress}%`, backgroundColor: goal.color }}
>
{/* Inner highlight for 3D effect */}
<div className="absolute top-0 left-0 right-0 h-1/2 bg-white/20"></div>
</div>
</div>
</div>
</div>
{/* Right Side: Milestones */}
<div className="w-full lg:w-96 rounded-sm bg-[#150F1D] border border-white/5 p-4 flex flex-col">
<div className="flex justify-between items-center mb-4">
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">Milestones</h3>
<button className="text-muted-foreground hover:text-foreground transition-colors"><MoreHorizontal className="h-4 w-4" /></button>
</div>
<div className="space-y-3 flex-1 overflow-y-auto tiny-scrollbar">
{goal.milestones.map((ms, idx) => (
<div key={idx} className="flex items-start gap-3">
{ms.done ? (
<CheckCircle2 className="h-4 w-4 shrink-0 mt-0.5" style={{ color: goal.color }} />
) : (
<CircleDashed className="h-4 w-4 text-muted-foreground shrink-0 mt-0.5" />
)}
<span className={`text-sm ${ms.done ? 'text-muted-foreground line-through' : 'text-foreground font-medium'}`}>
{ms.name}
</span>
</div>
))}
</div>
<button className="mt-4 w-full border border-dashed border-white/10 hover:border-white/30 text-muted-foreground hover:text-foreground py-2 rounded-sm text-xs font-semibold transition-colors flex items-center justify-center gap-2">
<Plus className="h-3 w-3" /> Add Milestone
</button>
</div>
</div>
))}
</div>
</div>
);
}
+180 -9
View File
@@ -1,17 +1,188 @@
"use client";
import { Plus, Filter, Brain, Check, X, Flame, Target, Trophy, TrendingUp } from "lucide-react";
import { Area, AreaChart, ResponsiveContainer, XAxis, Tooltip } from "recharts";
// Mock Data
const habits = [
{
id: 1,
name: "Morning Meditation",
category: "Mindfulness",
streak: 12,
goal: "Daily",
color: "#6C5BB0", // Primary
status: [true, true, true, false, true, true, false],
trend: [40, 45, 30, 60, 50, 70, 85]
},
{
id: 2,
name: "Read 20 Pages",
category: "Learning",
streak: 4,
goal: "Daily",
color: "#10b981", // Emerald
status: [false, true, true, true, true, false, false],
trend: [20, 40, 50, 40, 60, 80, 75]
},
{
id: 3,
name: "Gym Workout",
category: "Health",
streak: 2,
goal: "4x Week",
color: "#f97316", // Orange
status: [true, false, true, false, true, false, false],
trend: [50, 55, 45, 65, 60, 75, 90]
},
{
id: 4,
name: "No Sugar",
category: "Diet",
streak: 0,
goal: "Daily",
color: "#ef4444", // Red
status: [true, true, false, false, false, false, false],
trend: [80, 70, 60, 40, 30, 20, 10]
}
];
const days = ["M", "T", "W", "T", "F", "S", "S"];
export default function HabitsPage() {
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold tracking-tight text-foreground">Alışkanlıklar</h1>
<p className="text-muted-foreground mt-2">
Günlük alışkanlıklarınızı takip edin ve zinciri kırmayın.
</p>
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6">
{/* Top Header */}
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4">
<h1 className="text-lg font-medium text-muted-foreground">
<span className="text-foreground">Personal</span> / Habits Tracker
</h1>
<div className="flex items-center gap-3">
<button className="bg-[#150F1D] hover:bg-white/5 text-foreground border border-white/10 px-3 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
<Filter className="h-4 w-4" />
</button>
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
<Plus className="h-4 w-4" />
NEW HABIT
</button>
</div>
</div>
<div className="rounded-2xl border border-white/5 bg-white/5 p-8 text-center text-muted-foreground backdrop-blur-sm">
Alışkanlık takip modülü yakında eklenecek.
{/* AI Habit Optimizer */}
<div className="rounded-sm border border-primary/20 bg-[linear-gradient(90deg,rgba(108,91,176,0.1)_0%,rgba(10,7,16,0)_100%)] p-6 flex flex-col md:flex-row items-center justify-between gap-6">
<div className="flex items-start gap-4">
<div className="p-3 bg-primary/10 rounded-sm shrink-0">
<Brain className="h-6 w-6 text-primary" />
</div>
<div>
<h3 className="text-sm font-semibold text-primary mb-1 flex items-center gap-2">
AI Habit Optimizer
</h3>
<p className="text-xs text-foreground/80 leading-relaxed max-w-3xl">
I noticed a pattern: You often break your <strong>"No Sugar"</strong> streak on Thursdays. This correlates with high-stress days marked in your Journal. AI suggests scheduling a stress-relief activity (like a walk) around 3 PM on Thursdays to curb cravings.
</p>
</div>
</div>
<button className="bg-primary/20 text-primary hover:bg-primary/30 border border-primary/30 px-4 py-2 rounded-sm text-xs font-semibold transition-colors shrink-0">
Add Routine Intervention
</button>
</div>
{/* KPI Row */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-5 flex items-center justify-between">
<div>
<h4 className="text-[10px] uppercase tracking-wider text-muted-foreground font-bold mb-1">Perfect Days This Month</h4>
<div className="text-3xl font-bold text-foreground">8</div>
</div>
<Trophy className="h-10 w-10 text-emerald-500 opacity-20" />
</div>
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-5 flex items-center justify-between">
<div>
<h4 className="text-[10px] uppercase tracking-wider text-muted-foreground font-bold mb-1">Longest Active Streak</h4>
<div className="text-3xl font-bold text-foreground">12 <span className="text-sm text-muted-foreground font-normal">days</span></div>
</div>
<Flame className="h-10 w-10 text-orange-500 opacity-20" />
</div>
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-5 flex items-center justify-between">
<div>
<h4 className="text-[10px] uppercase tracking-wider text-muted-foreground font-bold mb-1">Overall Completion Rate</h4>
<div className="text-3xl font-bold text-foreground">68%</div>
</div>
<Target className="h-10 w-10 text-blue-500 opacity-20" />
</div>
</div>
{/* Habit Grid */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 pb-6">
{habits.map((habit) => (
<div key={habit.id} className="rounded-sm border border-white/5 bg-[#0A0710] p-6 flex flex-col group hover:border-white/10 transition-colors relative overflow-hidden">
{/* Top Info */}
<div className="flex justify-between items-start mb-6 z-10">
<div>
<h3 className="text-lg font-bold text-foreground mb-1">{habit.name}</h3>
<div className="flex gap-2 items-center">
<span className="text-[10px] uppercase tracking-wider font-bold px-2 py-0.5 rounded-sm bg-white/5 text-muted-foreground border border-white/5">{habit.category}</span>
<span className="text-xs text-muted-foreground flex items-center gap-1">
<Target className="h-3 w-3" /> {habit.goal}
</span>
</div>
</div>
<div className="flex flex-col items-end">
<span className="text-xs text-muted-foreground mb-0.5">Current Streak</span>
<div className="flex items-center gap-1.5 font-bold" style={{ color: habit.streak > 0 ? habit.color : '#8F89A5' }}>
<Flame className="h-4 w-4" /> {habit.streak}
</div>
</div>
</div>
{/* Weekly Checkboxes */}
<div className="flex justify-between items-center mb-6 z-10">
{days.map((day, idx) => (
<div key={idx} className="flex flex-col items-center gap-2">
<span className="text-[10px] font-bold text-muted-foreground">{day}</span>
<button
className="w-8 h-8 rounded-sm flex items-center justify-center transition-all border"
style={{
backgroundColor: habit.status[idx] ? `${habit.color}20` : '#150F1D',
borderColor: habit.status[idx] ? `${habit.color}50` : '#ffffff10',
color: habit.status[idx] ? habit.color : '#ffffff20'
}}
>
{habit.status[idx] ? <Check className="h-4 w-4" /> : <X className="h-3 w-3" />}
</button>
</div>
))}
</div>
{/* Micro Chart (Background styling) */}
<div className="h-16 w-full mt-auto relative z-0 opacity-50 group-hover:opacity-100 transition-opacity">
<div className="absolute top-0 left-0 text-[10px] text-muted-foreground uppercase tracking-widest font-bold flex items-center gap-1">
<TrendingUp className="h-3 w-3" /> 30-Day Trend
</div>
<ResponsiveContainer width="100%" height="100%">
<AreaChart data={habit.trend.map((val, i) => ({ name: i, value: val }))}>
<defs>
<linearGradient id={`grad-${habit.id}`} x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor={habit.color} stopOpacity={0.3}/>
<stop offset="95%" stopColor={habit.color} stopOpacity={0}/>
</linearGradient>
</defs>
<Tooltip
cursor={false}
contentStyle={{ display: 'none' }}
/>
<Area type="monotone" dataKey="value" stroke={habit.color} strokeWidth={2} fillOpacity={1} fill={`url(#grad-${habit.id})`} />
</AreaChart>
</ResponsiveContainer>
</div>
</div>
))}
</div>
</div>
);
}
+134 -228
View File
@@ -1,245 +1,151 @@
"use client";
import { useState } from "react";
import { useLiveQuery } from "dexie-react-hooks";
import { v4 as uuidv4 } from "uuid";
import { Plus, Search, Filter, Brain, PenTool, Calendar, AlignLeft, Tag, Lock, Sparkles, Image as ImageIcon } from "lucide-react";
import { analyzeJournalWithLocalAI } from "@/lib/ai";
import { db } from "@/lib/db";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
const moods = [
{ id: "happy", label: "Mutlu", emoji: "😊" },
{ id: "neutral", label: "Nötr", emoji: "😐" },
{ id: "sad", label: "Üzgün", emoji: "😔" },
{ id: "angry", label: "Sinirli", emoji: "😠" },
// Mock Data
const journalEntries = [
{
id: 1,
title: "Breakthrough in System Design",
preview: "Today we finally cracked the database architecture. By moving to a distributed model...",
date: "Today, 10:45 AM",
tags: ["Work", "Idea", "Win"],
sentiment: "Positive"
},
{
id: 2,
title: "Feeling a bit overwhelmed",
preview: "The Q3 deadlines are approaching fast. I need to make sure I'm prioritizing...",
date: "Yesterday",
tags: ["Mental Health", "Vent"],
sentiment: "Anxious"
},
{
id: 3,
title: "Morning Routine Reflection",
preview: "Woke up at 6 AM. Did 20 minutes of meditation. It really sets the tone for...",
date: "May 06, 2026",
tags: ["Habits", "Morning"],
sentiment: "Calm"
}
];
export default function JournalPage() {
const [content, setContent] = useState("");
const [mood, setMood] = useState("happy");
const [energy, setEnergy] = useState("3");
const [isSubmitting, setIsSubmitting] = useState(false);
// Dexie.js üzerinden günlükleri tarih sırasına göre çekiyoruz (en yeni en üstte).
const journals = useLiveQuery(() =>
db.journals.orderBy("date").reverse().toArray(),
);
const handleSubmit = async (event: React.FormEvent) => {
event.preventDefault();
if (!content.trim()) return;
setIsSubmitting(true);
const now = new Date().toISOString();
const entryId = uuidv4();
const currentContent = content;
try {
// Veriyi önce kaydet, AI analizini daha sonra arka planda tamamla.
await db.journals.add({
id: entryId,
date: now.split("T")[0],
mood,
energy: parseInt(energy, 10),
content: currentContent,
created_at: now,
updated_at: now,
});
setContent("");
setEnergy("3");
setMood("happy");
try {
const aiResult = await analyzeJournalWithLocalAI(currentContent);
if (aiResult) {
await db.journals.update(entryId, {
ai_tags: aiResult.ai_tags,
ai_sentiment_score: aiResult.ai_sentiment_score,
ai_summary: aiResult.ai_summary,
});
if (aiResult.suggested_tasks?.length) {
for (const taskTitle of aiResult.suggested_tasks) {
await db.tasks.add({
id: uuidv4(),
journal_id: entryId,
title: `AI Önerisi: ${taskTitle}`,
status: "todo",
ai_generated: true,
date: now.split("T")[0],
created_at: now,
});
}
}
}
} catch (aiError) {
console.error("Arka plan AI analizi hatası:", aiError);
}
} catch (error) {
console.error("Günlük kaydedilemedi:", error);
} finally {
setIsSubmitting(false);
}
};
const handleDelete = async (id: string) => {
if (confirm("Bu günlüğü silmek istediğinden emin misin?")) {
await db.journals.delete(id);
}
};
return (
<div className="mx-auto max-w-4xl animate-in space-y-6 fade-in slide-in-from-bottom-4 duration-500">
<div>
<h1 className="text-3xl font-bold tracking-tight">Günlük</h1>
<p className="text-muted-foreground">
Zihnini boşalt, hislerini kaydet. Verilerin sadece cihazında kalır.
</p>
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6">
{/* Top Header */}
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4">
<h1 className="text-lg font-medium text-muted-foreground">
<span className="text-foreground">Personal</span> / Daily Journal
</h1>
<div className="flex items-center gap-3">
<div className="bg-[#150F1D] border border-white/5 rounded-sm px-3 py-1.5 flex items-center gap-2">
<Search className="h-4 w-4 text-muted-foreground" />
<input
type="text"
placeholder="Search memories..."
className="bg-transparent border-none outline-none text-xs w-48 placeholder:text-muted-foreground/50 text-foreground"
/>
</div>
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
<Plus className="h-4 w-4" />
NEW ENTRY
</button>
</div>
</div>
<Card>
<CardHeader>
<CardTitle>Yeni Kayıt</CardTitle>
<CardDescription>Bugün nasıl hissediyorsun?</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit} className="space-y-4">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<div className="space-y-2">
<Label>Ruh Hali</Label>
<div className="flex gap-2">
{moods.map((currentMood) => (
<button
key={currentMood.id}
type="button"
onClick={() => setMood(currentMood.id)}
className={`flex flex-1 items-center justify-center rounded-md border px-1 py-2 text-xl transition-colors ${
mood === currentMood.id
? "border-primary bg-primary/20"
: "border-border bg-card hover:bg-muted"
}`}
title={currentMood.label}
>
{currentMood.emoji}
</button>
))}
</div>
</div>
{/* Main Layout */}
<div className="flex flex-col lg:flex-row gap-6 flex-1 min-h-0">
{/* Left Panel: Entry List & AI */}
<div className="w-full lg:w-80 flex flex-col gap-6 shrink-0">
{/* AI Sentiment Analysis */}
<div className="rounded-sm border border-primary/20 bg-[linear-gradient(135deg,rgba(108,91,176,0.1)_0%,rgba(10,7,16,0)_100%)] p-5">
<h3 className="text-sm font-semibold text-primary mb-2 flex items-center gap-2">
<Brain className="h-4 w-4" /> AI Reflection Insight
</h3>
<p className="text-[11px] text-foreground/80 leading-relaxed mb-3">
Over the last 14 days, your entries tagged with <strong>"Work"</strong> show a 30% increase in stress vocabulary. However, entries after <strong>Morning Meditation</strong> are consistently highly positive.
</p>
<button className="bg-primary/20 text-primary hover:bg-primary/30 border border-primary/30 px-3 py-1.5 rounded-sm text-[10px] font-bold uppercase tracking-wider transition-colors w-full">
Generate Weekly Summary
</button>
</div>
<div className="space-y-2">
<Label>Enerji Seviyesi (1-5): {energy}</Label>
<Input
type="range"
min="1"
max="5"
step="1"
value={energy}
onChange={(event) => setEnergy(event.target.value)}
className="w-full"
/>
</div>
{/* Entries List */}
<div className="flex-1 rounded-sm border border-white/5 bg-[#0A0710] flex flex-col overflow-hidden">
<div className="p-4 border-b border-white/5 flex justify-between items-center">
<span className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">Recent Entries</span>
<Filter className="h-4 w-4 text-muted-foreground hover:text-foreground cursor-pointer" />
</div>
<div className="space-y-2">
<Label htmlFor="content">Düşüncelerini buraya dök...</Label>
<Textarea
id="content"
value={content}
onChange={(event) => setContent(event.target.value)}
className="min-h-[150px] resize-y"
placeholder="Örneğin: Bugün toplantıda işler ters gitti..."
/>
</div>
<Button
type="submit"
disabled={isSubmitting}
className="w-full md:w-auto"
>
{isSubmitting ? "Kaydediliyor..." : "Kaydet"}
</Button>
</form>
</CardContent>
</Card>
<div className="space-y-4 pt-4">
<h2 className="text-xl font-bold">Geçmiş Kayıtlar</h2>
{!journals ? (
<p className="text-sm text-muted-foreground">Yükleniyor...</p>
) : journals.length === 0 ? (
<p className="text-sm text-muted-foreground">
Henüz kayıt bulunmuyor.
</p>
) : (
<div className="grid gap-4">
{journals.map((journal) => (
<Card key={journal.id}>
<CardHeader className="pb-2">
<div className="flex items-center justify-between">
<CardTitle className="flex items-center gap-2 text-base">
<span>
{moods.find((currentMood) => currentMood.id === journal.mood)
?.emoji ?? "📝"}
</span>
<span>{journal.date}</span>
</CardTitle>
<span className="rounded-md bg-muted px-2 py-1 text-xs font-medium text-muted-foreground">
Enerji: {journal.energy}/5
<div className="flex-1 overflow-y-auto tiny-scrollbar p-2 space-y-1">
{journalEntries.map((entry, idx) => (
<div key={entry.id} className={`p-3 rounded-sm cursor-pointer transition-colors ${idx === 0 ? 'bg-[#1F172B] border border-primary/30' : 'hover:bg-white/5 border border-transparent'}`}>
<h4 className="text-sm font-semibold text-foreground mb-1 truncate">{entry.title}</h4>
<p className="text-[11px] text-muted-foreground line-clamp-2 leading-relaxed mb-2">
{entry.preview}
</p>
<div className="flex justify-between items-center text-[10px]">
<span className="text-primary font-medium">{entry.date}</span>
<span className="flex gap-1">
{entry.tags.map(tag => (
<span key={tag} className="bg-white/10 px-1.5 py-0.5 rounded-sm">{tag}</span>
))}
</span>
</div>
</CardHeader>
<CardContent className="pt-2">
<p className="whitespace-pre-wrap text-sm leading-relaxed">
{journal.content}
</p>
{journal.ai_tags && (
<div className="mt-4 flex flex-wrap gap-2">
{journal.ai_tags.map((tag) => (
<span
key={tag}
className="rounded-md bg-primary/10 px-2 py-1 text-xs text-primary"
>
{tag}
</span>
))}
</div>
)}
{journal.ai_summary && (
<div className="mt-3 rounded-lg border border-l-2 border-l-primary bg-muted/40 p-3 text-sm italic text-muted-foreground">
&ldquo;{journal.ai_summary}&rdquo;
</div>
)}
<div className="mt-4 flex justify-end">
<Button
variant="ghost"
size="sm"
className="text-red-500 hover:bg-red-500/10 hover:text-red-600"
onClick={() => handleDelete(journal.id)}
>
Sil
</Button>
</div>
</CardContent>
</Card>
))}
</div>
))}
</div>
</div>
)}
</div>
{/* Right Panel: Editor Mock */}
<div className="flex-1 rounded-sm border border-white/5 bg-[#0A0710] flex flex-col relative overflow-hidden group">
{/* Editor Header */}
<div className="p-4 border-b border-white/5 flex justify-between items-center bg-[#0F0B15]/50">
<div className="flex items-center gap-4 text-xs text-muted-foreground">
<span className="flex items-center gap-1.5"><Calendar className="h-4 w-4" /> Today, 10:45 AM</span>
<span className="flex items-center gap-1.5"><Tag className="h-4 w-4" /> 3 Tags</span>
<span className="flex items-center gap-1.5"><Lock className="h-4 w-4" /> Private</span>
</div>
<div className="flex items-center gap-2">
<button className="p-1.5 hover:bg-white/10 rounded-sm text-muted-foreground transition-colors"><AlignLeft className="h-4 w-4" /></button>
<button className="p-1.5 hover:bg-white/10 rounded-sm text-muted-foreground transition-colors"><ImageIcon className="h-4 w-4" /></button>
<button className="p-1.5 hover:bg-primary/20 bg-primary/10 rounded-sm text-primary transition-colors flex items-center gap-1">
<Sparkles className="h-4 w-4" /> <span className="text-[10px] font-bold">Ask AI</span>
</button>
</div>
</div>
{/* Editor Body */}
<div className="flex-1 p-8 md:px-12 md:py-10 overflow-y-auto tiny-scrollbar">
<input
type="text"
value="Breakthrough in System Design"
readOnly
className="w-full bg-transparent border-none outline-none text-3xl font-bold text-foreground mb-6"
/>
<div className="text-foreground/80 leading-loose space-y-6 text-sm">
<p>
Today we finally cracked the database architecture. By moving to a distributed model, we've essentially solved the latency issues we were seeing during peak load. It feels incredibly satisfying to see weeks of research finally click into place.
</p>
<p>
I was discussing this with Alex earlier, and he pointed out that this structure directly mirrors the microservices split we planned for Q4. This means we are actually ahead of schedule!
</p>
<div className="pl-4 border-l-2 border-primary text-primary italic">
AI Note: You've mentioned "latency issues" in 3 previous entries. Consider documenting this final solution in the Engineering Wiki for future reference.
</div>
<p>
Gonna take the rest of the evening off to recharge. Need to keep this momentum going without burning out.
</p>
</div>
</div>
</div>
</div>
</div>
);
+188 -161
View File
@@ -1,174 +1,201 @@
"use client";
import { useState } from "react";
import { v4 as uuidv4 } from "uuid";
import { useLiveQuery } from "dexie-react-hooks";
import { db } from "@/lib/db";
import {
Card,
CardContent,
CardHeader,
CardTitle,
CardDescription,
} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Checkbox } from "@/components/ui/checkbox";
import { Trash2 } from "lucide-react";
import { Plus, Search, Filter, Brain, CheckSquare2, Clock, AlertCircle, MoreHorizontal, MessageSquare, ArrowUpRight, CheckCircle2 } from "lucide-react";
// Mock Data
const tasks = [
{
id: 1,
title: "Finalize Q3 Marketing Assets",
project: "Marketing Site",
priority: "High",
status: "In Progress",
assignee: "Sarah J.",
aiPredict: "2 days",
dueDate: "May 15"
},
{
id: 2,
title: "Database Migration Script",
project: "Infrastructure",
priority: "Critical",
status: "Review",
assignee: "Alex R.",
aiPredict: "4 hours",
dueDate: "May 12"
},
{
id: 3,
title: "Design System Tokens",
project: "Cognis Mobile",
priority: "Medium",
status: "To Do",
assignee: "Mike C.",
aiPredict: "3 days",
dueDate: "May 20"
},
{
id: 4,
title: "Client Interview Synthesis",
project: "Research",
priority: "Low",
status: "Done",
assignee: "Emma W.",
aiPredict: "Completed",
dueDate: "May 08"
},
{
id: 5,
title: "Optimize Webpack Config",
project: "Infrastructure",
priority: "Medium",
status: "To Do",
assignee: "Alex R.",
aiPredict: "1 day",
dueDate: "May 18"
}
];
export default function TasksPage() {
const [title, setTitle] = useState("");
const tasks = useLiveQuery(
() => db.tasks.toArray(), // Şimdilik hepsini çekiyoruz, sıralama yapılabilir
);
const handleAddTask = async (e: React.FormEvent) => {
e.preventDefault();
if (!title.trim()) return;
const now = new Date().toISOString();
try {
await db.tasks.add({
id: uuidv4(),
title,
status: "todo",
ai_generated: false,
date: now.split("T")[0],
created_at: now,
});
setTitle("");
} catch (error) {
console.error("Görev eklenemedi:", error);
}
};
const toggleTaskStatus = async (id: string, currentStatus: string) => {
await db.tasks.update(id, {
status: currentStatus === "todo" ? "completed" : "todo",
});
};
const deleteTask = async (id: string) => {
await db.tasks.delete(id);
};
const pendingTasks = tasks?.filter((t) => t.status === "todo") || [];
const completedTasks = tasks?.filter((t) => t.status === "completed") || [];
return (
<div className="space-y-6 max-w-4xl mx-auto animate-in fade-in slide-in-from-bottom-4 duration-500">
<div>
<h1 className="text-3xl font-bold tracking-tight">
Görevler & Planlar
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6">
{/* Top Header */}
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4">
<h1 className="text-lg font-medium text-muted-foreground">
<span className="text-foreground">Management</span> / Tasks
</h1>
<p className="text-muted-foreground">
Kişisel hedeflerin ve YZ tarafından önerilen aksiyonlar.
</p>
</div>
<Card>
<CardHeader>
<CardTitle>Yeni Görev</CardTitle>
<CardDescription>Aklındakini aksiyona dönüştür.</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleAddTask} className="flex gap-2">
<Input
placeholder="Örn: 15 dakika yürüyüş yap..."
value={title}
onChange={(e) => setTitle(e.target.value)}
className="flex-1"
<div className="flex items-center gap-3">
<div className="bg-[#150F1D] border border-white/5 rounded-sm px-3 py-1.5 flex items-center gap-2">
<Search className="h-4 w-4 text-muted-foreground" />
<input
type="text"
placeholder="Search tasks..."
className="bg-transparent border-none outline-none text-xs w-48 placeholder:text-muted-foreground/50 text-foreground"
/>
<Button type="submit">Ekle</Button>
</form>
</CardContent>
</Card>
<div className="grid gap-6 md:grid-cols-2 pt-4">
{/* Yapılacaklar */}
<div className="space-y-4">
<h2 className="text-xl font-semibold flex items-center gap-2">
Yapılacaklar{" "}
<span className="text-sm px-2 py-0.5 rounded-full bg-primary/20 text-primary">
{pendingTasks.length}
</span>
</h2>
<div className="space-y-2">
{pendingTasks.length === 0 ? (
<p className="text-sm text-muted-foreground">
Bekleyen görev yok.
</p>
) : (
pendingTasks.map((task) => (
<div
key={task.id}
className="flex items-center gap-3 p-3 rounded-lg border bg-card shadow-sm group transition-all hover:border-primary/50"
>
<Checkbox
checked={false}
onCheckedChange={() =>
toggleTaskStatus(task.id, task.status)
}
className="w-5 h-5"
/>
<span className="flex-1 text-sm font-medium">
{task.title}
</span>
<button
onClick={() => deleteTask(task.id)}
className="opacity-0 group-hover:opacity-100 p-1.5 text-muted-foreground hover:text-red-500 transition-all rounded-md hover:bg-red-500/10"
>
<Trash2 className="w-4 h-4" />
</button>
</div>
))
)}
</div>
</div>
{/* Tamamlananlar */}
<div className="space-y-4">
<h2 className="text-xl font-semibold opacity-70 flex items-center gap-2">
Tamamlananlar{" "}
<span className="text-sm px-2 py-0.5 rounded-full bg-muted text-muted-foreground">
{completedTasks.length}
</span>
</h2>
<div className="space-y-2">
{completedTasks.length === 0 ? (
<p className="text-sm text-muted-foreground">
Hiç görev tamamlanmadı.
</p>
) : (
completedTasks.map((task) => (
<div
key={task.id}
className="flex items-center gap-3 p-3 rounded-lg border bg-muted/40 shadow-sm group"
>
<Checkbox
checked={true}
onCheckedChange={() =>
toggleTaskStatus(task.id, task.status)
}
className="w-5 h-5 data-[state=checked]:bg-muted-foreground data-[state=checked]:border-muted-foreground"
/>
<span className="flex-1 text-sm line-through text-muted-foreground">
{task.title}
</span>
<button
onClick={() => deleteTask(task.id)}
className="opacity-0 group-hover:opacity-100 p-1.5 text-muted-foreground hover:text-red-500 transition-all rounded-md hover:bg-red-500/10"
>
<Trash2 className="w-4 h-4" />
</button>
</div>
))
)}
</div>
<button className="bg-[#150F1D] hover:bg-white/5 text-foreground border border-white/10 px-3 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
<Filter className="h-4 w-4" />
FILTER
</button>
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
<Plus className="h-4 w-4" />
NEW TASK
</button>
</div>
</div>
{/* AI Task Prioritization */}
<div className="rounded-sm border border-primary/20 bg-primary/5 p-6 flex flex-col md:flex-row items-start md:items-center justify-between gap-6">
<div className="flex items-start gap-4">
<div className="p-3 bg-primary/10 rounded-sm shrink-0">
<Brain className="h-6 w-6 text-primary" />
</div>
<div>
<h3 className="text-sm font-semibold text-primary mb-1 flex items-center gap-2">
AI Task Prioritization
</h3>
<p className="text-xs text-foreground/80 leading-relaxed max-w-2xl">
Based on the upcoming <strong>Infrastructure</strong> deadlines and <strong>Alex R.</strong>'s historical velocity, AI strongly suggests starting the <em>Database Migration Script</em> immediately. It has a high risk of cascading delays.
</p>
</div>
</div>
<button className="bg-primary/20 text-primary hover:bg-primary/30 border border-primary/30 px-4 py-2 rounded-sm text-xs font-semibold transition-colors shrink-0">
Auto-Sort Backlog
</button>
</div>
{/* Task List Header */}
<div className="flex items-center justify-between mt-2">
<div className="flex items-center gap-2">
<button className="px-3 py-1.5 text-xs font-medium rounded-sm bg-[#2B2538] text-foreground shadow-sm">List View</button>
<button className="px-3 py-1.5 text-xs font-medium rounded-sm text-muted-foreground hover:text-foreground transition-colors">Kanban Board</button>
</div>
<div className="text-xs text-muted-foreground font-medium">12 Active Tasks</div>
</div>
{/* Tasks Table */}
<div className="bg-[#0A0710] rounded-sm border border-white/5 overflow-hidden flex-1">
<div className="grid grid-cols-12 gap-4 p-4 border-b border-white/5 bg-[#0F0B15]/50 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
<div className="col-span-5">Task Details</div>
<div className="col-span-2">Status</div>
<div className="col-span-2">Assignee</div>
<div className="col-span-2">AI Time Estimate</div>
<div className="col-span-1 text-right">Actions</div>
</div>
<div className="divide-y divide-white/5">
{tasks.map((task) => (
<div key={task.id} className="grid grid-cols-12 gap-4 p-4 items-center hover:bg-white/[0.02] transition-colors group">
{/* Task Details */}
<div className="col-span-5 flex items-start gap-3">
<button className="mt-0.5 text-muted-foreground hover:text-primary transition-colors">
{task.status === "Done" ? <CheckCircle2 className="h-4 w-4 text-emerald-400" /> : <CheckSquare2 className="h-4 w-4" />}
</button>
<div>
<div className={`text-sm font-medium mb-1 ${task.status === 'Done' ? 'text-muted-foreground line-through' : 'text-foreground'}`}>
{task.title}
</div>
<div className="flex items-center gap-2">
<span className="text-[10px] text-muted-foreground font-medium bg-[#150F1D] px-2 py-0.5 rounded-sm border border-white/5">
{task.project}
</span>
<span className={`text-[10px] uppercase font-bold tracking-wider flex items-center gap-1 ${
task.priority === 'Critical' ? 'text-red-400' :
task.priority === 'High' ? 'text-orange-400' :
task.priority === 'Medium' ? 'text-blue-400' : 'text-muted-foreground'
}`}>
{task.priority === 'Critical' && <AlertCircle className="h-3 w-3" />}
{task.priority}
</span>
</div>
</div>
</div>
{/* Status */}
<div className="col-span-2">
<span className={`text-[10px] uppercase font-bold px-2 py-1 rounded-sm border inline-block ${
task.status === 'In Progress' ? 'bg-blue-500/10 text-blue-400 border-blue-500/20' :
task.status === 'Review' ? 'bg-orange-500/10 text-orange-400 border-orange-500/20' :
task.status === 'Done' ? 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20' :
'bg-white/5 text-muted-foreground border-white/10'
}`}>
{task.status}
</span>
</div>
{/* Assignee */}
<div className="col-span-2 flex items-center gap-2">
<div className="h-6 w-6 rounded-sm bg-[#1F172B] border border-white/10 flex items-center justify-center text-[10px] font-bold text-primary">
{task.assignee.split(' ')[0][0]}{task.assignee.split(' ')[1][0]}
</div>
<span className="text-xs text-muted-foreground">{task.assignee}</span>
</div>
{/* AI Estimate */}
<div className="col-span-2 flex items-center gap-2">
{task.status !== 'Done' && <Clock className="h-3.5 w-3.5 text-primary" />}
<span className={`text-xs ${task.status === 'Done' ? 'text-emerald-400 font-medium' : 'text-muted-foreground'}`}>
{task.aiPredict}
</span>
</div>
{/* Actions */}
<div className="col-span-1 flex justify-end gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
<button className="p-1.5 hover:bg-white/10 rounded-sm text-muted-foreground hover:text-foreground transition-colors">
<MessageSquare className="h-4 w-4" />
</button>
<button className="p-1.5 hover:bg-white/10 rounded-sm text-muted-foreground hover:text-foreground transition-colors">
<MoreHorizontal className="h-4 w-4" />
</button>
</div>
</div>
))}
</div>
</div>
</div>
);
}
+3 -11
View File
@@ -2,7 +2,6 @@ import type { Metadata } from "next";
import "./globals.css";
import { Geist } from "next/font/google";
import { cn } from "@/lib/utils";
import { ThemeProvider } from "@/components/theme-provider";
import { Toaster } from "react-hot-toast";
const geist = Geist({ subsets: ["latin"], variable: "--font-sans" });
@@ -20,19 +19,12 @@ export default function RootLayout({
return (
<html
lang="tr"
className={cn("font-sans", geist.variable)}
className={cn("font-sans dark", geist.variable)}
suppressHydrationWarning
>
<body>
<ThemeProvider
attribute="class"
defaultTheme="dark"
enableSystem
disableTransitionOnChange
>
{children}
<Toaster position="top-right" />
</ThemeProvider>
{children}
<Toaster position="top-right" />
</body>
</html>
);
+4 -4
View File
@@ -54,11 +54,11 @@ export const sidebarData: SidebarNavGroup[] = [
],
},
{
title: "ORGANİZASYON",
title: "FREELANCE",
items: [
{ title: "Ekip", href: "/team", icon: Users },
{ title: "Müşteriler", href: "/clients", icon: Building2 },
{ title: "Etiketler", href: "/tags", icon: Tags },
{ title: "Müşteriler (CRM)", href: "/freelance/clients", icon: Building2 },
{ title: "Teklifler & Sözleşmeler", href: "/freelance/proposals", icon: Tags },
{ title: "Zaman Takibi", href: "/freelance/time-tracking", icon: Activity },
],
},
{