File size: 3,231 Bytes
59bd45e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | import React, { useState } from 'react';
import { Plus } from 'lucide-react';
import { TodoItem } from '../types';
import { TodoCard } from './TodoCard';
import { PageHeader } from './PageHeader';
import { ChatDialog } from './ChatDialog';
interface TodoViewProps {
items: TodoItem[];
onClose: () => void;
onAdd?: () => void;
onToggleItem: (id: string) => void;
characterImageUrl?: string;
onSendMessage: (message: string) => Promise<string>;
}
export const TodoView: React.FC<TodoViewProps> = ({
items,
onClose,
onAdd,
onToggleItem,
characterImageUrl,
onSendMessage
}) => {
const [isChatOpen, setIsChatOpen] = useState(false);
// Sort: Not done first, then by time
const sortedItems = [...items].sort((a, b) => {
if (a.isDone === b.isDone) {
return (a.scheduledAt || 0) - (b.scheduledAt || 0);
}
return a.isDone ? 1 : -1;
});
return (
<div className="absolute inset-0 z-50 flex flex-col animate-[fadeIn_0.5s_ease-out]">
{/* Background Overlay */}
<div className="absolute inset-0 bg-gradient-to-br from-purple-50/95 via-pink-50/95 to-white/95 backdrop-blur-xl" />
{/* 页面头部 */}
<PageHeader
title="待办事项"
subtitle="One thing at a time"
onBack={onClose}
onChat={() => setIsChatOpen(true)}
characterImageUrl={characterImageUrl}
/>
{/* Scrollable List */}
<div className="relative z-10 flex-1 overflow-y-auto no-scrollbar scroll-smooth px-6 pt-2 pb-32">
<div className="w-full max-w-md mx-auto flex flex-col gap-2">
{sortedItems.map((item, index) => (
<TodoCard
key={item.id}
item={item}
index={index}
onToggle={onToggleItem}
location={item.location}
time={item.time}
/>
))}
</div>
</div>
{/* Floating Action Button */}
<div className="absolute bottom-24 right-6 z-30 opacity-0 animate-[fadeSlideUp_0.8s_ease-out_forwards] delay-300">
<button
onClick={onAdd}
className="
group relative flex items-center justify-center w-14 h-14
bg-white/60 backdrop-blur-xl rounded-full shadow-lg shadow-purple-100/50
ring-1 ring-white/60 text-purple-400
hover:bg-white/80 hover:text-purple-500 hover:scale-105
active:scale-95 transition-all duration-500
"
>
<Plus size={24} strokeWidth={1.5} className="group-hover:rotate-90 transition-transform duration-500" />
</button>
</div>
{/* 对话弹窗 */}
<ChatDialog
isOpen={isChatOpen}
onClose={() => setIsChatOpen(false)}
characterImageUrl={characterImageUrl}
onSendMessage={onSendMessage}
/>
<style>{`
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes fadeSlideDown { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } }
@keyframes fadeSlideUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
`}</style>
</div>
);
}; |