Files
digital-home-dashboard/src/components/widgets/TasksWidget.tsx
Cosmo f16318ff8e redesign: modern dark dashboard with gradients and animations
- New color system: deep #0a0a0f bg with indigo/violet/emerald accents
- Sidebar redesign: gradient DH badge, improved active state, cleaner typography
- Card system: .card class with colored top-border accents, hover glow
- WeatherWidget: large temperature display, gradient bg, better 7-day grid
- CalendarWidget: gradient today highlight, violet accents, improved events panel
- TasksWidget: priority dots, hover states, max-height scroll
- System page: circular SVG gauges with glow, accent cards, better bars
- Bookmarks page: hover lift effect, colored category headers
- Claude widgets: gradient badge headers, accent borders
- DashboardHeader: live clock, gradient greeting text
- ServicesGrid: pulsing online indicator (animate-ping), card lift on hover
- globals.css: Inter font, custom scrollbar, card/glass-card, gradient-text helper
- tailwind.config.ts: dash colors, gradient BG images, glow/float animations
2026-04-16 07:47:58 +00:00

81 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { CheckSquare, RefreshCw, Circle, CheckCircle2 } from "lucide-react";
import { useEffect, useState } from "react";
interface Task {
id: number;
title: string;
done?: boolean;
priority?: string;
}
export function TasksWidget() {
const [tasks, setTasks] = useState<Task[]>([]);
const [loading, setLoading] = useState(true);
const fetchTasks = async () => {
setLoading(true);
try {
const res = await fetch("/api/tasks");
const data = await res.json();
const list = data.tasks ?? data ?? [];
setTasks(Array.isArray(list) ? list : []);
} catch {
setTasks([]);
} finally {
setLoading(false);
}
};
useEffect(() => { fetchTasks(); }, []);
const priorityDot: Record<string, string> = {
high: "bg-red-500",
medium: "bg-amber-500",
low: "bg-emerald-500",
};
return (
<div className="card card-accent-emerald p-5">
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-2">
<CheckSquare className="w-4 h-4 text-emerald-400" />
<span className="text-sm font-semibold text-white">Задачи</span>
</div>
<button onClick={fetchTasks} className="text-slate-600 hover:text-slate-300 transition-colors p-1 rounded-lg hover:bg-white/5">
<RefreshCw className={`w-3.5 h-3.5 ${loading ? "animate-spin" : ""}`} />
</button>
</div>
{loading ? (
<div className="space-y-2 animate-pulse">
{[1,2,3].map(i => <div key={i} className="h-9 bg-white/5 rounded-xl" />)}
</div>
) : tasks.length === 0 ? (
<div className="flex flex-col items-center justify-center py-8 text-slate-600">
<CheckSquare className="w-8 h-8 mb-2 opacity-30" />
<span className="text-sm">Задач нет</span>
</div>
) : (
<div className="space-y-1.5 max-h-[320px] overflow-y-auto">
{tasks.map((task) => (
<div key={task.id} className="flex items-start gap-2.5 p-2.5 rounded-xl hover:bg-white/3 transition-colors group">
{task.done ? (
<CheckCircle2 className="w-4 h-4 text-emerald-400 shrink-0 mt-0.5" />
) : (
<Circle className="w-4 h-4 text-slate-600 shrink-0 mt-0.5 group-hover:text-slate-400 transition-colors" />
)}
<span className={`text-sm flex-1 ${task.done ? "text-slate-600 line-through" : "text-slate-200"}`}>
{task.title}
</span>
{task.priority && !task.done && (
<div className={`w-1.5 h-1.5 rounded-full shrink-0 mt-1.5 ${priorityDot[task.priority] ?? "bg-slate-600"}`} />
)}
</div>
))}
</div>
)}
</div>
);
}