现在开始构建这个功能完整的待办应用,我会专注于极简美学、流畅的拖拽交互和精致的动效。
```json{
"summary": "构建了一个支持拖拽排序和分类管理的待办应用,采用极简现代风格设计。左侧毛玻璃侧边栏展示分类列表(全部/个人/工作/学习),支持添加和删除分类;右侧主区域展示待办列表,支持添加、完成标记、删除和拖拽排序。使用Space Grotesk + Plus Jakarta Sans字体组合,柔和的蓝调渐变背景,每个分类配有专属色彩标识。交互上实现了拖拽视觉反馈、待办完成划线动画、添加/删除过渡动效、分类筛选切换等流畅体验。",
"widget": {
"type": "full-html",
"html": "<!DOCTYPE html><html lang=\"zh-CN\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>FlowTodo · 极简待办</title><link href=\"https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600…\" rel=\"stylesheet\"><link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.c…\"><script src=\"https://cdn.tailwindcss.com\"></script><style>:root{--primary:#6366f1;--primary-light:#eef2ff;--primary-dark:#4f46e5;--bg-start:#f0f4ff;--bg-end:#e8f0fe;--text-primary:#0f172a;--text-secondary:#64748b;--text-muted:#94a3b8;--border:#e2e8f0;--card:#ffffff;--shadow-sm:0 1px 3px rgba(0,0,0,0.04);--shadow-md:0 4px 16px rgba(0,0,0,0.06);--shadow-lg:0 12px 40px rgba(0,0,0,0.08);--radius:12px;--radius-lg:20px;--transition:250ms cubic-bezier(0.4,0,0.2,1)}*{margin:0;padding:0;box-sizing:border-box}body{font-family:'Plus Jakarta Sans',sans-serif;background:linear-gradient(135deg,var(--bg-start),var(--bg-end));min-height:100vh;color:var(--text-primary);-webkit-font-smoothing:antialiased}.font-display{font-family:'Space Grotesk',sans-serif}.app-container{max-width:1200px;margin:0 auto;padding:24px 20px;min-height:100vh;display:flex;gap:24px;align-items:flex-start}/* Sidebar */.sidebar{flex:0 0 260px;background:rgba(255,255,255,0.72);backdrop-filter:blur(20px) saturate(1.4);-webkit-backdrop-filter:blur(20px) saturate(1.4);border:1px solid rgba(255,255,255,0.6);border-radius:var(--radius-lg);padding:24px 0;box-shadow:var(--shadow-md);position:sticky;top:24px;max-height:calc(100vh - 48px);overflow-y:auto}.sidebar::-webkit-scrollbar{width:4px}.sidebar::-webkit-scrollbar-thumb{background:var(--text-muted);border-radius:4px}.sidebar::-webkit-scrollbar-track{background:transparent}.logo{padding:0 20px 20px;display:flex;align-items:center;gap:10px;border-bottom:1px solid var(--border);margin-bottom:16px}.logo-icon{width:36px;height:36px;background:linear-gradient(135deg,var(--primary),#a78bfa);border-radius:10px;display:flex;align-items:center;justify-content:center;color:#fff;font-size:18px;font-weight:700;font-family:'Space Grotesk',sans-serif;box-shadow:0 4px 12px rgba(99,102,241,0.3)}.logo-text{font-family:'Space Grotesk',sans-serif;font-size:20px;font-weight:700;background:linear-gradient(135deg,var(--text-primary),var(--primary));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}.category-item{display:flex;align-items:center;justify-content:space-between;padding:10px 20px;margin:2px 8px;border-radius:10px;cursor:pointer;transition:all var(--transition);position:relative}.category-item:hover{background:rgba(99,102,241,0.06)}.category-item.active{background:rgba(99,102,241,0.1)}.category-item.active .cat-name{font-weight:600;color:var(--primary)}.category-left{display:flex;align-items:center;gap:10px;min-width:0}.cat-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0;transition:transform var(--transition)}.category-item.active .cat-dot{transform:scale(1.3)}.cat-name{font-size:14px;font-weight:500;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cat-count{font-size:12px;font-weight:600;color:var(--text-muted);background:rgba(0,0,0,0.04);padding:2px 10px;border-radius:20px;flex-shrink:0;min-width:24px;text-align:center}.category-item.active .cat-count{background:rgba(99,102,241,0.15);color:var(--primary)}.cat-delete{opacity:0;width:20px;height:20px;border:none;background:rgba(239,68,68,0.1);border-radius:6px;color:#ef4444;font-size:10px;cursor:pointer;transition:all var(--transition);display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-left:4px}.category-item:hover .cat-delete{opacity:1}.cat-delete:hover{background:rgba(239,68,68,0.2);transform:scale(1.1)}.add-category-btn{display:flex;align-items:center;gap:8px;margin:12px 16px 0;padding:10px 14px;border:1.5px dashed var(--border);border-radius:10px;background:transparent;color:var(--text-secondary);font-size:13px;font-weight:500;cursor:pointer;transition:all var(--transition);width:calc(100% - 32px);font-family:'Plus Jakarta Sans',sans-serif}.add-category-btn:hover{border-color:var(--primary);color:var(--primary);background:rgba(99,102,241,0.04)}.add-category-form{padding:12px 16px 0;display:none}.add-category-form.show{display:block}.add-category-form input{width:100%;padding:8px 12px;border:1.5px solid var(--border);border-radius:8px;font-size:13px;font-family:'Plus Jakarta Sans',sans-serif;outline:none;transition:border var(--transition)}.add-category-form input:focus{border-color:var(--primary);box-shadow:0 0 0 3px rgba(99,102,241,0.1)}.add-category-actions{display:flex;gap:6px;margin-top:8px}.add-category-actions button{padding:6px 14px;border-radius:8px;font-size:12px;font-weight:600;cursor:pointer;border:none;transition:all var(--transition);font-family:'Plus Jakarta Sans',sans-serif}.btn-confirm{background:var(--primary);color:#fff}.btn-confirm:hover{background:var(--primary-dark)}.btn-cancel{background:rgba(0,0,0,0.05);color:var(--text-secondary)}.btn-cancel:hover{background:rgba(0,0,0,0.08)}/* Main */.main{flex:1;min-width:0}.main-header{background:rgba(255,255,255,0.72);backdrop-filter:blur(20px) saturate(1.4);-webkit-backdrop-filter:blur(20px) saturate(1.4);border:1px solid rgba(255,255,255,0.6);border-radius:var(--radius-lg);padding:20px 24px 16px;box-shadow:var(--shadow-sm);margin-bottom:16px}.main-header-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:4px}.main-title{font-family:'Space Grotesk',sans-serif;font-size:22px;font-weight:700;color:var(--text-primary)}.main-subtitle{font-size:13px;color:var(--text-muted);font-weight:500}.stats{display:flex;gap:16px;align-items:center}.stat-item{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--text-secondary);font-weight:500}.stat-item i{font-size:11px;color:var(--text-muted)}.stat-number{font-weight:700;color:var(--text-primary);font-family:'Space Grotesk',sans-serif;font-size:14px}.stat-number.completed{color:#10b981}.stat-number.pending{color:var(--primary)}/* Add Todo */.add-todo-bar{background:rgba(255,255,255,0.72);backdrop-filter:blur(20px) saturate(1.4);-webkit-backdrop-filter:blur(20px) saturate(1.4);border:1px solid rgba(255,255,255,0.6);border-radius:var(--radius);padding:12px 16px;box-shadow:var(--shadow-sm);margin-bottom:12px;display:flex;gap:10px;align-items:center}.add-todo-bar input{flex:1;border:none;background:transparent;font-size:14px;font-family:'Plus Jakarta Sans',sans-serif;color:var(--text-primary);outline:none;padding:6px 0}.add-todo-bar input::placeholder{color:var(--text-muted)}.add-todo-bar select{padding:6px 12px;border:1.5px solid var(--border);border-radius:8px;font-size:12px;font-family:'Plus Jakarta Sans',sans-serif;background:#fff;color:var(--text-primary);outline:none;cursor:pointer;transition:border var(--transition)}.add-todo-bar select:focus{border-color:var(--primary)}.add-todo-btn{width:36px;height:36px;border:none;border-radius:10px;background:linear-gradient(135deg,var(--primary),#a78bfa);color:#fff;font-size:14px;cursor:pointer;transition:all var(--transition);display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 2px 8px rgba(99,102,241,0.25)}.add-todo-btn:hover{transform:scale(1.05);box-shadow:0 4px 16px rgba(99,102,241,0.35)}.add-todo-btn:active{transform:scale(0.95)}/* Todo List */.todo-list{display:flex;flex-direction:column;gap:8px}.todo-item{background:rgba(255,255,255,0.85);backdrop-filter:blur(12px) saturate(1.2);-webkit-backdrop-filter:blur(12px) saturate(1.2);border:1px solid rgba(255,255,255,0.5);border-radius:var(--radius);padding:0 16px 0 0;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:12px;transition:all var(--transition);cursor:default;position:relative;overflow:hidden;animation:fadeSlideIn 0.35s cubic-bezier(0.4,0,0.2,1) both}.todo-item:hover{box-shadow:var(--shadow-md);border-color:rgba(99,102,241,0.15)}.todo-item.dragging{opacity:0.4;transform:scale(0.97);box-shadow:var(--shadow-sm)}.todo-item.drag-over{border-color:var(--primary);box-shadow:0 0 0 2px rgba(99,102,241,0.15);transform:translateY(2px)}.todo-item .color-bar{width:4px;align-self:stretch;flex-shrink:0;border-radius:4px 0 0 4px;transition:background var(--transition)}.drag-handle{padding:12px 0 12px 12px;cursor:grab;color:var(--text-muted);font-size:14px;opacity:0.3;transition:all var(--transition);display:flex;align-items:center;flex-shrink:0}.todo-item:hover .drag-handle{opacity:0.6}.drag-handle:active{cursor:grabbing}.todo-checkbox{position:relative;width:20px;height:20px;flex-shrink:0}.todo-checkbox input{position:absolute;opacity:0;width:100%;height:100%;cursor:pointer;z-index:2}.todo-checkbox .checkmark{width:20px;height:20px;border:2px solid var(--border);border-radius:6px;display:flex;align-items:center;justify-content:center;transition:all var(--transition);position:absolute;top:0;left:0;background:#fff}.todo-checkbox input:hover+.checkmark{border-color:var(--primary)}.todo-checkbox input:checked+.checkmark{background:linear-gradient(135deg,var(--primary),#a78bfa);border-color:var(--primary)}.todo-checkbox input:checked+.checkmark::after{content:'\\f00c';font-family:'Font Awesome 6 Free';font-weight:900;font-size:10px;color:#fff}.todo-text{flex:1;font-size:14px;font-weight:500;color:var(--text-primary);padding:14px 0;transition:all var(--transition);min-width:0;word-break:break-word}.todo-item.completed .todo-text{text-decoration:line-through;color:var(--text-muted)}.todo-cat-tag{font-size:11px;font-weight:600;padding:3px 10px;border-radius:20px;background:rgba(0,0,0,0.04);color:var(--text-muted);flex-shrink:0;transition:all var(--transition);white-space:nowrap}.todo-delete{width:28px;height:28px;border:none;border-radius:8px;background:transparent;color:var(--text-muted);font-size:13px;cursor:pointer;transition:all var(--transition);display:flex;align-items:center;justify-content:center;flex-shrink:0;opacity:0}.todo-item:hover .todo-delete{opacity:0.5}.todo-delete:hover{opacity:1!important;background:rgba(239,68,68,0.1);color:#ef4444}/* Empty State */.empty-state{background:rgba(255,255,255,0.5);border:1.5px dashed var(--border);border-radius:var(--radius-lg);padding:48px 20px;text-align:center;display:flex;flex-direction:column;align-items:center;gap:12px}.empty-state i{font-size:40px;color:var(--text-muted);opacity:0.4}.empty-state h3{font-family:'Space Grotesk',sans-serif;font-size:16px;font-weight:600;color:var(--text-secondary)}.empty-state p{font-size:13px;color:var(--text-muted)}/* Animations */@keyframes fadeSlideIn{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeIn{from{opacity:0}to{opacity:1}}@keyframes slideDown{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}@keyframes pulse-dot{0%,100%{transform:scale(1)}50%{transform:scale(1.3)}}.fade-in{animation:fadeIn 0.3s ease both}.slide-down{animation:slideDown 0.3s ease both}.todo-item.removing{opacity:0;transform:translateX(30px);transition:all 0.25s cubic-bezier(0.4,0,0.2,1)}/* Scrollbar */.todo-list-container{max-height:calc(100vh - 280px);overflow-y:auto;padding-right:2px}.todo-list-container::-webkit-scrollbar{width:4px}.todo-list-container::-webkit-scrollbar-thumb{background:var(--border);border-radius:4px}.todo-list-container::-webkit-scrollbar-track{background:transparent}/* Responsive */@media(max-width:768px){.app-container{flex-direction:column;padding:16px 12px;gap:12px}.sidebar{flex:none;width:100%;position:static;max-height:none;padding:16px 0;border-radius:var(--radius)}.logo{padding:0 16px 14px}.category-item{padding:8px 16px;margin:1px 6px}.category-scroll{display:flex;gap:4px;overflow-x:auto;padding:0 12px 8px;scrollbar-width:none;-ms-overflow-style:none}.category-scroll::-webkit-scrollbar{display:none}.category-scroll .category-item{flex-shrink:0;margin:0}.add-category-btn{width:auto;margin:8px 12px 0;flex-shrink:0}.add-category-form{padding:8px 12px 0}.main-header{padding:16px 18px}.main-title{font-size:18px}.main-header-top{flex-direction:column;align-items:flex-start;gap:6px}.stats{gap:12px}.add-todo-bar{padding:10px 14px;flex-wrap:wrap}.add-todo-bar select{width:auto}.todo-list-container{max-height:none;overflow-y:visible}.todo-item{padding:0 12px 0 0}.drag-handle{padding:10px 0 10px 10px;font-size:12px}.todo-text{font-size:13px;padding:12px 0}.todo-cat-tag{font-size:10px;padding:2px 8px}}@media(max-width:480px){.app-container{padding:12px 8px;gap:8px}.sidebar{border-radius:10px;padding:12px 0}.main-header{border-radius:10px;padding:14px 14px}.add-todo-bar{border-radius:10px;padding:8px 12px;gap:8px}.add-todo-bar input{font-size:13px}.add-todo-bar select{font-size:11px;padding:4px 8px}.add-todo-btn{width:32px;height:32px;font-size:12px}.todo-item{border-radius:10px}.stats{flex-wrap:wrap;gap:8px}.stat-item{font-size:11px}}/* Page Load Animation */.sidebar{animation:fadeSlideIn 0.45s cubic-bezier(0.4,0,0.2,1) both}.main-header{animation:fadeSlideIn 0.45s cubic-bezier(0.4,0,0.2,1) 0.08s both}.add-todo-bar{animation:fadeSlideIn 0.45s cubic-bezier(0.4,0,0.2,1) 0.16s both}.todo-item:nth-child(1){animation-delay:0.24s}.todo-item:nth-child(2){animation-delay:0.30s}.todo-item:nth-child(3){animation-delay:0.36s}.todo-item:nth-child(4){animation-delay:0.42s}.todo-item:nth-child(5){animation-delay:0.48s}.todo-item:nth-child(n+6){animation-delay:0.52s}</style></head><body><div class=\"app-container\" id=\"app\"><!-- Sidebar --><aside class=\"sidebar\" id=\"sidebar\"><div class=\"logo\"><div class=\"logo-icon\">✓</div><span class=\"logo-text\">FlowTodo</span></div><div class=\"category-scroll\" id=\"categoryList\"></div><button class=\"add-category-btn\" id=\"addCategoryBtn\"><i class=\"fas fa-plus\"></i> 新建分类</button><div class=\"add-category-form\" id=\"addCategoryForm\"><input type=\"text\" id=\"categoryInput\" placeholder=\"输入分类名称...\" maxlength=\"12\"><div class=\"add-category-actions\"><button class=\"btn-confirm\" id=\"confirmCategory\">添加</button><button class=\"btn-cancel\" id=\"cancelCategory\">取消</button></div></div></aside><!-- Main --><main class=\"main\"><div class=\"main-header\"><div class=\"main-header-top\"><h1 class=\"main-title\" id=\"currentCategoryTitle\">全部待办</h1><div class=\"stats\"><span class=\"stat-item\"><i class=\"far fa-circle\"></i> 待办 <span class=\"stat-number pending\" id=\"pendingCount\">0</span></span><span class=\"stat-item\"><i class=\"fas fa-check-circle\"></i> 已完成 <span class=\"stat-number completed\" id=\"completedCount\">0</span></span></div></div><div class=\"main-subtitle\" id=\"subtitle\">共 0 项任务</div></div><!-- Add Todo --><div class=\"add-todo-bar\"><input type=\"text\" id=\"todoInput\" placeholder=\"添加新待办... 回车快速创建\" maxlength=\"100\"><select id=\"todoCategorySelect\"></select><button class=\"add-todo-btn\" id=\"addTodoBtn\"><i class=\"fas fa-plus\"></i></button></div><!-- Todo List --><div class=\"todo-list-container\" id=\"todoListContainer\"><div class=\"todo-list\" id=\"todoList\"></div></div></main></div><script>// ===================== STATE =====================const COLORS={personal:'#f59e0b',work:'#3b82f6',study:'#10b981',other:'#8b5cf6',all:'#6366f1'};const ICONS={personal:'user',work:'briefcase',study:'book',other:'tag',all:'layer-group'};const CATEGORY_NAMES={personal:'个人',work:'工作',study:'学习',other:'其他'};let state={categories:[{id:'personal',name:'个人'},{id:'work',name:'工作'},{id:'study',name:'学习'},{id:'other',name:'其他'}],todos:[{id:Date.now()+1,text:'欢迎使用 FlowTodo 🎉',completed:false,category:'personal',order:0},{id:Date.now()+2,text:'拖拽左侧手柄可以排序任务',completed:false,category:'work',order:1},{id:Date.now()+3,text:'点击分类筛选查看不同任务',completed:false,category:'study',order:2},{id:Date.now()+4,text:'标记完成的任务会显示划线效果',completed:true,category:'personal',order:3},{id:Date.now()+5,text:'试试新建分类管理你的生活',completed:false,category:'work',order:4}],currentCategory:'all',nextOrder:5,dragSource:null};// ===================== DOM REFS =====================const $=(s)=>document.querySelector(s);const $$=(s)=>document.querySelectorAll(s);const catList=$('#categoryList');const todoList=$('#todoList');const catTitle=$('#currentCategoryTitle');const subtitle=$('#subtitle');const pendingCount=$('#pendingCount');const completedCount=$('#completedCount');const todoInput=$('#todoInput');const todoCatSelect=$('#todoCategorySelect');const addTodoBtn=$('#addTodoBtn');const addCatBtn=$('#addCategoryBtn');const addCatForm=$('#addCategoryForm');const catInput=$('#categoryInput');const confirmCat=$('#confirmCategory');const cancelCat=$('#cancelCategory');// ===================== HELPERS =====================function genId(){return Date.now()+Math.floor(Math.random()*1000)}function getCategoryColor(id){return COLORS[id]||'#6366f1'}function getCategoryName(id){if(id==='all')return'全部';return CATEGORY_NAMES[id]||id}function getCategoryIcon(id){return ICONS[id]||'tag'}function getFilteredTodos(){const cat=state.currentCategory;if(cat==='all')return[...state.todos].sort((a,b)=>a.order-b.order);return state.todos.filter(t=>t.category===cat).sort((a,b)=>a.order-b.order)}function getCategoryCount(catId){if(catId==='all')return state.todos.length;return state.todos.filter(t=>t.category===catId).length}function getPendingCount(){const filtered=getFilteredTodos();return filtered.filter(t=>!t.completed).length}function getCompletedCount(){const filtered=getFilteredTodos();return filtered.filter(t=>t.completed).length}// ===================== RENDER =====================function renderCategories(){let html='';// "全部" always firsthtml+=`<div class=\"category-item ${state.currentCategory==='all'?'active':''}\" data-cat=\"all\"><div class=\"category-left\"><span class=\"cat-dot\" style=\"background:${COLORS.all}\"></span><span class=\"cat-name\">全部</span></div><span class=\"cat-count\">${getCategoryCount('all')}</span></div>`;state.categories.forEach(cat=>{const cnt=getCategoryCount(cat.id);const isActive=state.currentCategory===cat.id;html+=`<div class=\"category-item ${isActive?'active':''}\" data-cat=\"${cat.id}\"><div class=\"category-left\"><span class=\"cat-dot\" style=\"background:${getCategoryColor(cat.id)}\"></span><span class=\"cat-name\">${cat.name}</span></div><div style=\"display:flex;align-items:center;gap:4px\"><span class=\"cat-count\">${cnt}</span><button class=\"cat-delete\" data-cat=\"${cat.id}\" title=\"删除分类\"><i class=\"fas fa-times\"></i></button></div></div>`;});catList.innerHTML=html;// Bind category clickscatList.querySelectorAll('.category-item').forEach(el=>{el.addEventListener('click',(e)=>{if(e.target.closest('.cat-delete'))return;const catId=el.dataset.cat;switchCategory(catId);});});// Bind deletecatList.querySelectorAll('.cat-delete').forEach(btn=>{btn.addEventListener('click',(e)=>{e.stopPropagation();const catId=btn.dataset.cat;deleteCategory(catId);});});renderCategorySelect();renderStats();renderTitle();}function renderCategorySelect(){const cur=state.currentCategory==='all'?'personal':state.currentCategory;let html=`<option value=\"personal\">个人</option><option value=\"work\">工作</option><option value=\"study\">学习</option><option value=\"other\">其他</option>`;state.categories.forEach(cat=>{const exists=['personal','work','study','other'].includes(cat.id);if(!exists){html+=`<option value=\"${cat.id}\">${cat.name}</option>`;}});todoCatSelect.innerHTML=html;todoCatSelect.value=cur;}function renderTodos(){const todos=getFilteredTodos();if(todos.length===0){todoList.innerHTML=`<div class=\"empty-state\"><i class=\"far fa-clipboard\"></i><h3>还没有待办事项</h3><p>在上方输入框中添加你的第一条任务吧</p></div>`;renderStats();renderTitle();return;}let html='';todos.forEach((todo,idx)=>{const color=getCategoryColor(todo.category);const catName=getCategoryName(todo.category);html+=`<div class=\"todo-item ${todo.completed?'completed':''}\" draggable=\"true\" data-id=\"${todo.id}\" data-order=\"${todo.order}\"><div class=\"color-bar\" style=\"background:${color}\"></div><div class=\"drag-handle\" draggable=\"false\"><i class=\"fas fa-grip-vertical\"></i></div><label class=\"todo-checkbox\"><input type=\"checkbox\" ${todo.completed?'checked':''} data-id=\"${todo.id}\"><span class=\"checkmark\"></span></label><span class=\"todo-text\">${escapeHtml(todo.text)}</span><span class=\"todo-cat-tag\" style=\"color:${color};background:${color}15\">${catName}</span><button class=\"todo-delete\" data-id=\"${todo.id}\" title=\"删除\"><i class=\"fas fa-trash-can\"></i></button></div>`;});todoList.innerHTML=html;renderStats();renderTitle();bindTodoEvents();}function renderStats(){const todos=getFilteredTodos();const pending=getPendingCount();const completed=getCompletedCount();pendingCount.textContent=pending;completedCount.textContent=completed;subtitle.textContent=`共 ${todos.length} 项任务`;}function renderTitle(){const name=getCategoryName(state.currentCategory);catTitle.textContent=state.currentCategory==='all'?'全部待办':`${name} · 待办`;}// ===================== EVENTS =====================function bindTodoEvents(){// CheckboxtodoList.querySelectorAll('.todo-checkbox input').forEach(cb=>{cb.addEventListener('change',function(){toggleTodo(parseInt(this.dataset.id));});});// DeletetodoList.querySelectorAll('.todo-delete').forEach(btn=>{btn.addEventListener('click',function(){deleteTodo(parseInt(this.dataset.id));});});// Drag & Droplet items=todoList.querySelectorAll('.todo-item');items.forEach(item=>{item.addEventListener('dragstart',handleDragStart);item.addEventListener('dragend',handleDragEnd);item.addEventListener('dragover',handleDragOver);item.addEventListener('dragenter',handleDragEnter);item.addEventListener('dragleave',handleDragLeave);item.addEventListener('drop',handleDrop);});}let dragSrcId=null;function handleDragStart(e){const item=e.target.closest('.todo-item');if(!item)return;dragSrcId=parseInt(item.dataset.id);item.classList.add('dragging');e.dataTransfer.effectAllowed='move';e.dataTransfer.setData('text/plain',item.dataset.id);// Style drag imageconst ghost=item.cloneNode(true);ghost.style.position='absolute';ghost.style.top='-1000px';ghost.style.opacity='0.6';ghost.style.transform='rotate(2deg)';ghost.style.boxShadow='0 20px 60px rgba(0,0,0,0.15)';ghost.style.borderRadius='12px';document.body.appendChild(ghost);e.dataTransfer.setDragImage(ghost,20,20);setTimeout(()=>document.body.removeChild(ghost),0);}function handleDragEnd(e){const item=e.target.closest('.todo-item');if(!item)return;item.classList.remove('dragging');document.querySelectorAll('.todo-item').forEach(el=>el.classList.remove('drag-over'));dragSrcId=null;}function handleDragOver(e){e.preventDefault();e.dataTransfer.dropEffect='move';const item=e.target.closest('.todo-item');if(!item||parseInt(item.dataset.id)===dragSrcId)return;item.classList.add('drag-over');}function handleDragEnter(e){e.preventDefault();const item=e.target.closest('.todo-item');if(!item)return;item.classList.add('drag-over');}function handleDragLeave(e){const item=e.target.closest('.todo-item');if(!item)return;item.classList.remove('drag-over');}function handleDrop(e){e.preventDefault();const item=e.target.closest('.todo-item');if(!item)return;item.classList.remove('drag-over');const targetId=parseInt(item.dataset.id);if(!dragSrcId||dragSrcId===targetId)return;const filtered=getFilteredTodos();const srcIndex=filtered.findIndex(t=>t.id===dragSrcId);const targetIndex=filtered.findIndex(t=>t.id===targetId);if(srcIndex===-1||targetIndex===-1)return;// Reorder in the full listconst srcTodo=state.todos.find(t=>t.id===dragSrcId);if(!srcTodo)return;// Get all todos in current categoryconst catTodos=state.todos.filter(t=>{const cat=state.currentCategory;return cat==='all'||t.category===cat;}).sort((a,b)=>a.order-b.order);// Remove src from arrayconst srcIdx=catTodos.findIndex(t=>t.id===dragSrcId);if(srcIdx===-1)return;const [removed]=catTodos.splice(srcIdx,1);// Insert at target positionconst tgtIdx=catTodos.findIndex(t=>t.id===targetId);if(tgtIdx===-1){catTodos.push(removed);}else{catTodos.splice(tgtIdx,0,removed);}// Update orderscatTodos.forEach((t,i)=>{const fullTodo=state.todos.find(f=>f.id===t.id);if(fullTodo)fullTodo.order=i;});renderTodos();}// ===================== ACTIONS =====================function switchCategory(catId){state.currentCategory=catId;renderCategories();renderTodos();}function addTodo(text,category){if(!text.trim())return;const exists=['personal','work','study','other'];if(!exists.includes(category)&&!state.categories.find(c=>c.id===category)){category='personal';}const maxOrder=state.todos.reduce((max,t)=>Math.max(max,t.order),-1);state.todos.push({id:genId(),text:text.trim(),completed:false,category,order:maxOrder+1});renderTodos();renderCategories();todoInput.value='';todoInput.focus();}function deleteTodo(id){const todo=state.todos.find(t=>t.id===id);if(!todo)return;// Animate removalconst el=todoList.querySelector(`.todo-item[data-id=\"${id}\"]`);if(el){el.classList.add('removing');setTimeout(()=>{state.todos=state.todos.filter(t=>t.id!==id);renderTodos();renderCategories();},250);}else{state.todos=state.todos.filter(t=>t.id!==id);renderTodos();renderCategories();}}function toggleTodo(id){const todo=state.todos.find(t=>t.id===id);if(!todo)return;todo.completed=!todo.completed;renderTodos();renderCategories();}function deleteCategory(catId){if(catId==='all')return;const cat=state.categories.find(c=>c.id===catId);if(!cat)return;const count=state.todos.filter(t=>t.category===catId).length;if(count>0&&!confirm(`「${cat.name}」分类下有 ${count} 项待办,删除分类后这些待办将被移至「其他」分类,确定删除吗?`)){return;}state.todos.forEach(t=>{if(t.category===catId){t.category='other';}});state.categories=state.categories.filter(c=>c.id!==catId);if(state.currentCategory===catId)state.currentCategory='all';renderCategories();renderTodos();}function addCategory(name){const trimmed=name.trim();if(!trimmed)return;const id=trimmed.toLowerCase().replace(/\\s+/g,'-').replace(/[^a-z0-9\\u4e00-\\u9fa5\\-]/g,'');if(!id||state.categories.find(c=>c.id===id)||['all'].includes(id)){alert('分类名无效或已存在');return;}COLORS[id]=['#f43f5e','#f97316','#84cc16','#14b8a6','#06b6d4','#8b5cf6','#d946ef','#ec4899'][state.categories.length%8];CATEGORY_NAMES[id]=trimmed;ICONS[id]='tag';state.categories.push({id,name:trimmed});renderCategories();catInput.value='';addCatForm.classList.remove('show');}function escapeHtml(text){const d=document.createElement('div');d.textContent=text;return d.innerHTML;}// ===================== INIT =====================function init(){renderCategories();renderTodos();// Add todo eventstodoInput.addEventListener('keydown',(e)=>{if(e.key==='Enter'){const text=todoInput.value.trim();const cat=todoCatSelect.value;if(text){addTodo(text,cat);}}});addTodoBtn.addEventListener('click',()=>{const text=todoInput.value.trim();const cat=todoCatSelect.value;if(text)addTodo(text,cat);});// Category form toggleaddCatBtn.addEventListener('click',()=>{addCatForm.classList.toggle('show');if(addCatForm.classList.contains('show')){catInput.focus();}});confirmCat.addEventListener('click',()=>{addCategory(catInput.value);});cancelCat.addEventListener('click',()=>{addCatForm.classList.remove('show');catInput.value='';});catInput.addEventListener('keydown',(e)=>{if(e.key==='Enter'){addCategory(catInput.value);}else if(e.key==='Escape'){addCatForm.classList.remove('show');catInput.value='';}});// Click outside to close category formdocument.addEventListener('click',(e)=>{if(!e.target.closest('.add-category-form')&&!e.target.closest('#addCategoryBtn')){addCatForm.classList.remove('show');}});}document.addEventListener('DOMContentLoaded',init);</script></body></html>"
},
"next": "[\"新增标签筛选\",\"主题色切换\",\"数据导出功能\",\"番茄钟计时\",\"日历视图集成\"]",
"breakpoint": "none"
}
```