style: format code for improved readability and consistency across multiple files

This commit is contained in:
Poyraz Avsever
2026-05-06 16:20:27 +03:00
parent c73bf0e499
commit 983c8fd6aa
9 changed files with 295 additions and 110 deletions
+1 -1
View File
@@ -55,4 +55,4 @@
body {
@apply bg-background text-foreground;
}
}
}
+45 -15
View File
@@ -5,7 +5,14 @@ import { v4 as uuidv4 } from "uuid";
import { useLiveQuery } from "dexie-react-hooks";
import { db } from "@/lib/db";
import { analyzeJournalWithLocalAI } from "@/lib/ai";
import { Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter } from "@/components/ui/card";
import {
Card,
CardContent,
CardHeader,
CardTitle,
CardDescription,
CardFooter,
} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
@@ -25,8 +32,8 @@ export default function JournalPage() {
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 journals = useLiveQuery(() =>
db.journals.orderBy("date").reverse().toArray(),
);
const handleSubmit = async (e: React.FormEvent) => {
@@ -83,7 +90,6 @@ export default function JournalPage() {
} catch (aiErr) {
console.error("Arka plan AI analizi hatası:", aiErr);
}
} catch (error) {
console.error("Günlük kaydedilemedi:", error);
} finally {
@@ -92,7 +98,7 @@ export default function JournalPage() {
};
const handleDelete = async (id: string) => {
if(confirm("Bu günlüğü silmek istediğinden emin misin?")) {
if (confirm("Bu günlüğü silmek istediğinden emin misin?")) {
await db.journals.delete(id);
}
};
@@ -101,7 +107,9 @@ export default function JournalPage() {
<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ünlük</h1>
<p className="text-muted-foreground">Zihnini boşalt, hislerini kaydet. Verilerin sadece cihazında kalır.</p>
<p className="text-muted-foreground">
Zihnini boşalt, hislerini kaydet. Verilerin sadece cihazında kalır.
</p>
</div>
<Card>
@@ -121,7 +129,9 @@ export default function JournalPage() {
type="button"
onClick={() => setMood(m.id)}
className={`flex-1 py-2 px-1 rounded-md border text-xl flex items-center justify-center transition-colors ${
mood === m.id ? "bg-primary/20 border-primary" : "bg-card border-border hover:bg-muted"
mood === m.id
? "bg-primary/20 border-primary"
: "bg-card border-border hover:bg-muted"
}`}
title={m.label}
>
@@ -155,7 +165,11 @@ export default function JournalPage() {
/>
</div>
<Button type="submit" disabled={isSubmitting} className="w-full md:w-auto">
<Button
type="submit"
disabled={isSubmitting}
className="w-full md:w-auto"
>
{isSubmitting ? "Kaydediliyor..." : "Kaydet"}
</Button>
</form>
@@ -167,7 +181,9 @@ export default function JournalPage() {
{!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>
<p className="text-sm text-muted-foreground">
Henüz kayıt bulunmuyor.
</p>
) : (
<div className="grid gap-4">
{journals.map((journal) => (
@@ -175,7 +191,9 @@ export default function JournalPage() {
<CardHeader className="pb-2">
<div className="flex items-center justify-between">
<CardTitle className="text-base flex items-center gap-2">
<span>{moods.find(m => m.id === journal.mood)?.emoji}</span>
<span>
{moods.find((m) => m.id === journal.mood)?.emoji}
</span>
<span>{journal.date}</span>
</CardTitle>
<span className="text-xs px-2 py-1 bg-muted rounded-md font-medium text-muted-foreground">
@@ -184,13 +202,18 @@ export default function JournalPage() {
</div>
</CardHeader>
<CardContent className="pt-2">
<p className="whitespace-pre-wrap text-sm leading-relaxed">{journal.content}</p>
<p className="whitespace-pre-wrap text-sm leading-relaxed">
{journal.content}
</p>
{/* AI Sonuçlarını Göster */}
{journal.ai_tags && (
<div className="mt-4 flex flex-wrap gap-2">
{journal.ai_tags.map(tag => (
<span key={tag} className="text-xs px-2 py-1 bg-primary/10 text-primary rounded-md">
{journal.ai_tags.map((tag) => (
<span
key={tag}
className="text-xs px-2 py-1 bg-primary/10 text-primary rounded-md"
>
{tag}
</span>
))}
@@ -203,7 +226,14 @@ export default function JournalPage() {
)}
<div className="flex justify-end mt-4">
<Button variant="ghost" size="sm" className="text-red-500 hover:text-red-600 hover:bg-red-500/10" onClick={() => handleDelete(journal.id)}>Sil</Button>
<Button
variant="ghost"
size="sm"
className="text-red-500 hover:text-red-600 hover:bg-red-500/10"
onClick={() => handleDelete(journal.id)}
>
Sil
</Button>
</div>
</CardContent>
</Card>
+10 -6
View File
@@ -6,7 +6,7 @@ import { ThemeProvider } from "@/components/theme-provider";
import { Sidebar } from "@/components/layout/sidebar";
import { Header } from "@/components/layout/header";
const geist = Geist({subsets:['latin'],variable:'--font-sans'});
const geist = Geist({ subsets: ["latin"], variable: "--font-sans" });
export const metadata: Metadata = {
title: "MindSpace",
@@ -19,13 +19,17 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
<html lang="tr" className={cn("font-sans", geist.variable)} suppressHydrationWarning>
<html
lang="tr"
className={cn("font-sans", geist.variable)}
suppressHydrationWarning
>
<body>
<ThemeProvider
attribute="class"
defaultTheme="dark"
enableSystem
disableTransitionOnChange
attribute="class"
defaultTheme="dark"
enableSystem
disableTransitionOnChange
>
<div className="flex min-h-screen bg-background text-foreground">
<Sidebar />
+141 -47
View File
@@ -15,27 +15,36 @@ import {
ResponsiveContainer,
BarChart,
Bar,
Legend
Legend,
} from "recharts";
const moodScores: Record<string, number> = { happy: 4, neutral: 3, sad: 2, angry: 1 };
const moodScores: Record<string, number> = {
happy: 4,
neutral: 3,
sad: 2,
angry: 1,
};
export default function DashboardPage() {
const journals = useLiveQuery(() => db.journals.orderBy("date").toArray()) || [];
const journals =
useLiveQuery(() => db.journals.orderBy("date").toArray()) || [];
const tasks = useLiveQuery(() => db.tasks.toArray()) || [];
const pendingTasksCount = tasks.filter(t => t.status === "todo").length;
const pendingTasksCount = tasks.filter((t) => t.status === "todo").length;
// Bugüne ait enerji seviyesi
const today = new Date().toISOString().split("T")[0];
const todaysJournal = journals.find(j => j.date === today);
const todaysJournal = journals.find((j) => j.date === today);
const todaysEnergy = todaysJournal ? todaysJournal.energy : "--";
// 1. Grafik: Son 7 günün Ruh Hali ve Enerji trendi
const trendData = useMemo(() => {
const dataMap: Record<string, { date: string, moodSum: number, energySum: number, count: number }> = {};
journals.forEach(j => {
const dataMap: Record<
string,
{ date: string; moodSum: number; energySum: number; count: number }
> = {};
journals.forEach((j) => {
if (!dataMap[j.date]) {
dataMap[j.date] = { date: j.date, moodSum: 0, energySum: 0, count: 0 };
}
@@ -45,7 +54,7 @@ export default function DashboardPage() {
});
return Object.values(dataMap)
.map(d => ({
.map((d) => ({
date: d.date.slice(5), // Sadece MM-DD formatı alalım
Mood: Number((d.moodSum / d.count).toFixed(1)),
Enerji: Number((d.energySum / d.count).toFixed(1)),
@@ -56,9 +65,9 @@ export default function DashboardPage() {
// 2. Grafik: En çok kullanılan AI etiketleri
const tagData = useMemo(() => {
const counts: Record<string, number> = {};
journals.forEach(j => {
journals.forEach((j) => {
if (j.ai_tags) {
j.ai_tags.forEach(tag => {
j.ai_tags.forEach((tag) => {
counts[tag] = (counts[tag] || 0) + 1;
});
}
@@ -70,45 +79,55 @@ export default function DashboardPage() {
}, [journals]);
// Son günlüğe ait AI Summary
const lastInsight = [...journals].reverse().find(j => j.ai_summary)?.ai_summary;
const lastInsight = [...journals]
.reverse()
.find((j) => j.ai_summary)?.ai_summary;
return (
<div className="space-y-6 max-w-6xl mx-auto animate-in fade-in slide-in-from-bottom-4 duration-500">
<div className="flex flex-col gap-2">
<h1 className="text-3xl font-bold tracking-tight">Bugün Nasılsın?</h1>
<p className="text-muted-foreground">Kişisel özetin ve yapay zeka analizlerin burada görünecek.</p>
<p className="text-muted-foreground">
Kişisel özetin ve yapay zeka analizlerin burada görünecek.
</p>
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<Card>
<CardHeader className="flex flex-row items-center justify-between pb-2 space-y-0">
<CardTitle className="text-sm font-medium">Günlük Kayıtları</CardTitle>
<CardTitle className="text-sm font-medium">
Günlük Kayıtları
</CardTitle>
<PenTool className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{journals.length}</div>
<p className="text-xs text-muted-foreground mt-1">
{journals.length === 0 ? "Henüz kayıt girilmedi" : "Toplam kayıt eklendi"}
{journals.length === 0
? "Henüz kayıt girilmedi"
: "Toplam kayıt eklendi"}
</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between pb-2 space-y-0">
<CardTitle className="text-sm font-medium">Aktif Görevler</CardTitle>
<CardTitle className="text-sm font-medium">
Aktif Görevler
</CardTitle>
<CheckCircle className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{pendingTasksCount}</div>
<p className="text-xs text-muted-foreground mt-1">
Bekleyen görev
</p>
<p className="text-xs text-muted-foreground mt-1">Bekleyen görev</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between pb-2 space-y-0">
<CardTitle className="text-sm font-medium">Bugünkü Enerji</CardTitle>
<CardTitle className="text-sm font-medium">
Bugünkü Enerji
</CardTitle>
<Activity className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
@@ -121,7 +140,9 @@ export default function DashboardPage() {
<Card>
<CardHeader className="flex flex-row items-center justify-between pb-2 space-y-0">
<CardTitle className="text-sm font-medium">Local AI Durumu</CardTitle>
<CardTitle className="text-sm font-medium">
Local AI Durumu
</CardTitle>
<Brain className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
@@ -137,57 +158,128 @@ export default function DashboardPage() {
{/* Line Chart */}
<Card className="lg:col-span-4 p-6 flex flex-col justify-between">
<div className="mb-4">
<h3 className="text-lg font-medium mb-1">Ruh Hali & Enerji Trendi</h3>
<p className="text-sm text-muted-foreground">Son 7 günlük ortalamalar (1-5 Arası Puanlama)</p>
<h3 className="text-lg font-medium mb-1">
Ruh Hali & Enerji Trendi
</h3>
<p className="text-sm text-muted-foreground">
Son 7 günlük ortalamalar (1-5 Arası Puanlama)
</p>
</div>
<div className="h-[250px] w-full">
{trendData.length > 0 ? (
<ResponsiveContainer width="100%" height="100%">
<LineChart data={trendData}>
<CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#88888833" />
<XAxis dataKey="date" axisLine={false} tickLine={false} tick={{ fontSize: 12 }} />
<YAxis domain={[1, 5]} axisLine={false} tickLine={false} tick={{ fontSize: 12 }} width={30} />
<Tooltip
contentStyle={{ borderRadius: "8px", backgroundColor: "#fff", color: "#000", border: "none" }}
<CartesianGrid
strokeDasharray="3 3"
vertical={false}
stroke="#88888833"
/>
<XAxis
dataKey="date"
axisLine={false}
tickLine={false}
tick={{ fontSize: 12 }}
/>
<YAxis
domain={[1, 5]}
axisLine={false}
tickLine={false}
tick={{ fontSize: 12 }}
width={30}
/>
<Tooltip
contentStyle={{
borderRadius: "8px",
backgroundColor: "#fff",
color: "#000",
border: "none",
}}
itemStyle={{ fontWeight: "500" }}
/>
<Legend wrapperStyle={{ paddingTop: "10px", fontSize: "14px" }} />
<Line type="monotone" dataKey="Mood" stroke="#3b82f6" strokeWidth={3} dot={{ r: 4 }} activeDot={{ r: 6 }} />
<Line type="monotone" dataKey="Enerji" stroke="#10b981" strokeWidth={3} dot={{ r: 4 }} activeDot={{ r: 6 }} />
<Legend
wrapperStyle={{ paddingTop: "10px", fontSize: "14px" }}
/>
<Line
type="monotone"
dataKey="Mood"
stroke="#3b82f6"
strokeWidth={3}
dot={{ r: 4 }}
activeDot={{ r: 6 }}
/>
<Line
type="monotone"
dataKey="Enerji"
stroke="#10b981"
strokeWidth={3}
dot={{ r: 4 }}
activeDot={{ r: 6 }}
/>
</LineChart>
</ResponsiveContainer>
) : (
<div className="h-full flex items-center justify-center border-2 border-dashed rounded-md bg-muted/20">
<p className="text-sm text-muted-foreground">Veri bekleniyor...</p>
<p className="text-sm text-muted-foreground">
Veri bekleniyor...
</p>
</div>
)}
</div>
</Card>
{/* Bar Chart & Insight */}
<div className="lg:col-span-3 space-y-4 flex flex-col">
<Card className="p-6 flex-1 flex flex-col">
<div className="mb-4">
<h3 className="text-lg font-medium mb-1">AI Konu Dağılımı</h3>
<p className="text-sm text-muted-foreground">Günlüklerinden çıkarılan en sık 5 etiket</p>
<p className="text-sm text-muted-foreground">
Günlüklerinden çıkarılan en sık 5 etiket
</p>
</div>
<div className="h-[150px] w-full mt-auto">
{tagData.length > 0 ? (
<ResponsiveContainer width="100%" height="100%">
<BarChart data={tagData} layout="vertical" margin={{ left: -20 }}>
<CartesianGrid strokeDasharray="3 3" horizontal={false} stroke="#88888833" />
<BarChart
data={tagData}
layout="vertical"
margin={{ left: -20 }}
>
<CartesianGrid
strokeDasharray="3 3"
horizontal={false}
stroke="#88888833"
/>
<XAxis type="number" hide />
<YAxis dataKey="name" type="category" axisLine={false} tickLine={false} tick={{ fontSize: 13 }} width={90} />
<Tooltip
cursor={{fill: 'transparent'}}
contentStyle={{ borderRadius: "8px", backgroundColor: "#fff", color: "#000", border: "none" }}
<YAxis
dataKey="name"
type="category"
axisLine={false}
tickLine={false}
tick={{ fontSize: 13 }}
width={90}
/>
<Tooltip
cursor={{ fill: "transparent" }}
contentStyle={{
borderRadius: "8px",
backgroundColor: "#fff",
color: "#000",
border: "none",
}}
/>
<Bar
dataKey="Değer"
fill="#8b5cf6"
radius={[0, 4, 4, 0]}
barSize={20}
/>
<Bar dataKey="Değer" fill="#8b5cf6" radius={[0, 4, 4, 0]} barSize={20} />
</BarChart>
</ResponsiveContainer>
) : (
<div className="h-full flex items-center justify-center border-2 border-dashed rounded-md bg-muted/20">
<p className="text-sm text-muted-foreground">Yeterli etiket yok.</p>
<p className="text-sm text-muted-foreground">
Yeterli etiket yok.
</p>
</div>
)}
</div>
@@ -198,7 +290,9 @@ export default function DashboardPage() {
<Brain className="w-5 h-5 text-primary" /> Son AI İçgörüsü
</h3>
<p className="text-sm text-foreground/80 leading-relaxed italic">
{lastInsight ? `"${lastInsight}"` : "Henüz bir içgörü oluşmadı. Biraz günlük yaz, AI analiz yapsın."}
{lastInsight
? `"${lastInsight}"`
: "Henüz bir içgörü oluşmadı. Biraz günlük yaz, AI analiz yapsın."}
</p>
</Card>
</div>
+66 -26
View File
@@ -4,7 +4,13 @@ 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 {
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";
@@ -14,7 +20,7 @@ export default function TasksPage() {
const [title, setTitle] = useState("");
const tasks = useLiveQuery(
() => db.tasks.toArray() // Şimdilik hepsini çekiyoruz, sıralama yapılabilir
() => db.tasks.toArray(), // Şimdilik hepsini çekiyoruz, sıralama yapılabilir
);
const handleAddTask = async (e: React.FormEvent) => {
@@ -48,14 +54,18 @@ export default function TasksPage() {
await db.tasks.delete(id);
};
const pendingTasks = tasks?.filter(t => t.status === "todo") || [];
const completedTasks = tasks?.filter(t => t.status === "completed") || [];
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</h1>
<p className="text-muted-foreground">Kişisel hedeflerin ve YZ tarafından önerilen aksiyonlar.</p>
<h1 className="text-3xl font-bold tracking-tight">
Görevler & Planlar
</h1>
<p className="text-muted-foreground">
Kişisel hedeflerin ve YZ tarafından önerilen aksiyonlar.
</p>
</div>
<Card>
@@ -65,8 +75,8 @@ export default function TasksPage() {
</CardHeader>
<CardContent>
<form onSubmit={handleAddTask} className="flex gap-2">
<Input
placeholder="Örn: 15 dakika yürüyüş yap..."
<Input
placeholder="Örn: 15 dakika yürüyüş yap..."
value={title}
onChange={(e) => setTitle(e.target.value)}
className="flex-1"
@@ -80,21 +90,36 @@ export default function TasksPage() {
{/* 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>
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>
<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)}
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">
<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>
@@ -106,21 +131,36 @@ export default function TasksPage() {
{/* 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>
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>
<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)}
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">
<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>